为什么我这麽菜呀
A
思想不够,数据结构来凑,树状数组打了出来,很快的,过了。
但显然有只要把\(1\)的个数存下来,每次单点修改的时候计算总的\(1\)的个数就完了。
总结:我真傻,真的
B
首先题一定要申请呀呀呀呀呀呀呀呀呀
显然最多只用移动两步就可以了,那麽我们只需判断所有相邻两行障碍物的横向距离的最大值,
如果这个最大指大于\(1\),那麽就不用移动,直接输出\(0\)
如果这个最大值为\(1\),那麽只用移动一步,输出\(min(u,v)\)
如果这个最大值为\(0\),那麽只用移动\(2\)步,这时首先必须进行横向移动,然后进行横向或纵向,因此此时输出\(min(u+v,v+v)\)
n=read(),u=read(),v=read();
int tmp=-1;
rep(i,1,n) a[i]=read();
rep(i,2,n) tmp=max(tmp,abs(a[i]-a[i-1]));
if(tmp==0) {
print(min(u+v,v+v));
}
else if(tmp>1) print(0);
else print(min(u,v));
pts;
C
我太菜了
一个很显然的贪心,每次从第一个出发一定能取得最小的答案,不要相信样例的步骤,谁知道它是不是在误导你,那麽我们直接模拟肯定是不行的,对于每一个位置,它一定会转移到\((i+2,min(i+S_i,n))\)区间内所有的元素,那麽我们不妨令\(d[i]\)表示第\(i\)个位置消减的次数,
对于每个元素首先将它嫩便利到的位置\(d[i]++\),
随后如果当前位置\(d[i]\)大于\(S_i-1\),说明此时早已变为1,那麽踩到这里会自动到下一个位置,那麽\(d[i+1]+=d[i]-S_i+1\)
否则,\(ans+=S_i-1-d[i],d[i+1]\)不变
T=read();
while(T--){
ll ans=0;
n=read();
rep(i,1,n)s[i]=read(),d[i]=0;
rep(i,1,n){
rep(j,i+2,min(i+s[i],n)) d[j]++;
if(d[i]<s[i]-1) ans+=s[i]-1-d[i],d[i]=s[i]-1;
d[i+1]+=abs(d[i]-s[i]+1);
}
print(ans);pts;
}
D
这个\(u\)通向\(u+v\)的条件是\(u\&v=v\),
二进制数\(101000\)可以来自\(11000,100110,100111,100100\),我们可以发现将用二进制分解后,
\(u_i\)到\(v_i\)时,\(u_i\)上的1的个数一定大于等于\(v_i的个数\),因为\(\&\)的操作位\(00100\)这种时,每次只是将二进制每个位置上的1向左移动,1的数量不会发生变化。当操作\(001100\)时,1的数目可能变少,但不会变多。
其次因为\(v_i\)中的1可以拆解至较小位的若干个1,因此\(v_i\)只要依次的1的位置均不小于\(u_i\)的相应位置,那麽\(v_i\)上的1均可以通过一些变化来满足\(u_i\)的条件。
因此\(u_i\)到\(v_i\)的条件是:
1:\(u_i<=v_i\)
2:\(v_i\)中1的个数小于等于\(u_i\)
3: \(v_i\)与\(u_i\)的从小到大的二进制位为1的位置应满足\(v_i\)的大于\(u_i\)的,因为高位的1可以右移和变多。
bool solve(){
if(x>y) return 0;
a.clear();b.clear();
rep(i,0,29) if(x&(1<<i)) a.pb(i);
rep(i,0,29) if(y&(1<<i)) b.pb(i);
if(b.size()>a.size()) return 0;
int k=min(b.size(),a.size());
rep(i,0,k-1){
if(b[i]<a[i]) return 0;
}
return 1;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in0.txt","r",stdin);
#endif
n=read();
while(n--){
x=read(),y=read();
if(solve()) puts("YES");
else puts("NO");
}
return 0;
}
E
这个题思路很显然,就是dfs,在dfs中如果当前子树的大小刚好为斐波那契数列的某一项,那麽就一定可以继续分,而dfs又可以满足从小子树到大子树,在小子树无法形成斐波那契树,那麽更大的树一定无法形成。
因此,我们以当前应分的两个子树的大小为关键字进行dfs,然后如果当前子树大小可以满足啊,那麽断掉这条边,继续向下验证,直至返回答案
int n;
int f[maxn];
int sze[maxn];
int last[maxn],cnt=1;
struct Edge{
int v,nxt,cut;
}edge[maxn<<1];
void add(int u,int v){
edge[++cnt].v=v;edge[cnt].nxt=last[u];
last[u]=cnt;edge[cnt].cut=0;
}
bool dfs(int now,int fa,int x,int y){
sze[now]=1;
if(f[x]==1||f[y]==1) return 1;
for(int i=last[now];i;i=edge[i].nxt){
int to=edge[i].v;
if(to==fa||edge[i].cut==1) continue;
if(dfs(to,now,x,y)) return 1;
if(sze[to]==f[y]){
edge[i].cut=edge[i^1].cut=1;
return dfs(to,to,y-2,y-1)&dfs(now,now,x-2,x-1);
}
if(sze[to]==f[x]){
edge[i].cut=edge[i^1].cut=1;
return dfs(to,to,x-2,x-1)&dfs(now,now,y-2,y-1);
}
sze[now]+=sze[to];
}
return 0;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in2.txt","r",stdin);
#endif
n=read();
if(n<=3) {puts("YES");return 0;}
f[0]=f[1]=1;int pos;
rep(i,2,n){
f[i]=f[i-1]+f[i-2];
if(f[i]==n) {pos=i;break;}
if(f[i]>n) {
puts("NO");
return 0;
}
}
int x,y;
rep(i,1,n-1){
x=read(),y=read();
add(x,y);add(y,x);
}
if(dfs(1,0,pos-2,pos-1)) puts("YES");
else puts("NO");
return 0;
}
F
题意
你有 \(n\)个磁铁,每个磁铁有属性,为下列三种之一
\(N、S、-\)(表示无磁性)
一次操作你可以选择不相交的两个磁铁的子集 \(S\) 和 \(T\),假设 S 中有 n1 个 N,s1 个 S, T 中有 n2 个 N,s2 个 S。这些你都不知道。通过交互库你可以得到 n1n2−n1s2−n2s1+s1s2(化简得到:(n1−s1)(n2−s2) )。得到的数值可能 <0。
你可以花费不超过 n+⌊log2n⌋ 次操作找出所有没有磁性的磁铁。
多组数据 T≤100,每次 n≤2000,∑n≤2000。保证至少两个有磁极的磁铁和一个无磁极的磁铁
做法
如果我们能够找到一个有磁性的位置,那麽我们一定能够通过这个位置来得到其他位置\(1\)的所有情况,那麽我们就需要想办法找出一个带磁性的的位置。
我们不妨每次查询位置i和i之前的所有元素,如果结果为\(0\),说明\(i\)是无磁性或者\(i-1\)之前均为无磁性的,但如果结果不为\(0\),那么说明\(i\)之前绝对存在有磁性的,且由于我们是从前向后遍历,因此\(i\)之前有且仅有一个有磁性的,此时\(i\)一定也为有磁性的。
那么我们就可以用位置\(i\)将后面的元素一个一个的判断出来,至此,复杂度为\(O(n)\),之后的\(logn\)用到二分上,我们每次询问\(1~mid\)和\(i\),然后找到i之前的哪一个有磁性的磁铁,至此,复杂度为\(O(n-1+logn)\)
int T;
int n;
vector<int>ans;
int ask(int pos,int l,int r){
printf("? 1 %d\n",r-l+1);
print(pos);pts;
rep(i,l,r) print(i),ptc;
pts;
fflush(stdout);
return read();
}
int main(){
T=read();
while(T--){
n=read();
ans.clear();
rep(i,2,n){
int k=ask(i,1,i-1);
if(k==0) continue;
rep(j,i+1,n) {
int tmp=ask(i,j,j);
if(tmp==0) ans.pb(j);
}
int l=1,r=i-1,pos;
while(l<=r){
int mid=(l+r)>>1;
if(ask(i,1,mid)) r=mid-1,pos=mid;
else l=mid+1;
}
rep(j,1,i-1) {
if(j!=pos) ans.pb(j);
}
break;
}
printf("! %d ",ans.size());
int x=ans.size();
rep(i,0,x-1) print(ans[i]),ptc;
pts;fflush(stdout);
}
return 0;
}