Good Bye 2019

比赛链接

\({\frak{A. Card Game}}\)

显然,二者最大值大的人赢。

\({\frak{code:}}\)

    #include<bits/stdc++.h>
    #define IL inline
    #define LL long long 
    using namespace std;
    int n,n1,n2,Max1,Max2;
    IL int in(){
    	char c;int f=1;
    	while((c=getchar())<'0'||c>'9')
    	  if(c=='-') f=-1;
    	int x=c-'0';
    	while((c=getchar())>='0'&&c<='9')
    	  x=x*10+c-'0';
    	return x*f;
    }
    int main()
    {
    	int t=in();
    	while(t--){
    		n1=in(),n2=in(),Max1=Max2=0;
    		while(n1--) Max1=max(Max1,in());
    		while(n2--) Max2=max(Max2,in());
    		puts(Max1<Max2?"NO":"YES");
    	}
    	return 0;
    }

\({\frak{B. Interesting Subarray}}\)

若相邻两个元素的差值都小于\(2\),则不可能找出满足条件的序列。故只需要检查相邻元素即可。

\({\frak{code:}}\)

    #include<bits/stdc++.h>
    #define IL inline
    #define LL long long 
    using namespace std;
    const int N=2e5+3;
    int n,a[N],l,r,Max,Min;
    IL int in(){
    	char c;int f=1;
    	while((c=getchar())<'0'||c>'9')
    	  if(c=='-') f=-1;
    	int x=c-'0';
    	while((c=getchar())>='0'&&c<='9')
    	  x=x*10+c-'0';
    	return x*f;
    }
    int main()
    {
    	int t=in();
    	while(t--){
    		n=in();
    		for(int i=1;i<=n;++i) a[i]=in();
    		for(int i=1;i<n;++i) 
    		  if(abs(a[i]-a[i+1])>=2){
    			puts("YES");printf("%d %d\n",i,i+1);goto dd;
    		}
    		puts("NO");
    		dd:;
    	}
    	return 0;
    }

\({\frak{C. Make Good}}\)

异或与和进行比较不好处理,考虑先加一个数\(xor\)等于原数组的异或和,使异或值等于零,再加上\(sum+xor\)即可完成构造。

(因为\(LL\)输出\(\%lld\) \(WA\)了两次。。。)

\({\frak{code:}}\)

    #include<bits/stdc++.h>
    #define IL inline
    #define LL long long 
    using namespace std;
    const int N=1e5+3;
    int n,a[N],xo;
    LL sum;
    IL int in(){
    	char c;int f=1;
    	while((c=getchar())<'0'||c>'9')
    	  if(c=='-') f=-1;
    	int x=c-'0';
    	while((c=getchar())>='0'&&c<='9')
    	  x=x*10+c-'0';
    	return x*f;
    }
    void write(LL x){
    	if(x>9) write(x/10);
    	putchar(x%10+'0');
    }
    int main()
    {
    	int t=in();
    	while(t--){
    		n=in(),sum=xo=0;
    		for(int i=1;i<=n;++i) a[i]=in(),sum+=a[i],xo^=a[i];
    		write(2),putchar('\n'),write(xo),putchar(' '),write(sum+xo),putchar('\n');
    	}
    	return 0;
    }

\({\frak{D. Strange Device}}\)

显然只需询问\(k+1\)个元素,询问相当于删去一个数问第\(m\)个数。我们发现答案只有两种情况,二者的较小数的出现次数便是\(m\)

\({\frak{code:}}\)

    #include<bits/stdc++.h>
    #define IL inline
    #define LL long long 
    using namespace std;
    const int N=5e2+3;
    int n,k,a[N],res,m1,m2,n1,n2;
    LL sum;
    IL int in(){
    	char c;int f=1;
    	while((c=getchar())<'0'||c>'9')
    	  if(c=='-') f=-1;
    	int x=c-'0';
    	while((c=getchar())>='0'&&c<='9')
    	  x=x*10+c-'0';
    	return x*f;
    }
    void write(LL x){
    	if(x>9) write(x/10);
    	putchar(x%10+'0');
    }
    int main()
    {
    		n=in(),k=in(),m1=m2=-1,n1=n2=0;
    		for(int i=1;i<=k+1;++i){
    			printf("?");
    			for(int j=1;j<=k+1;++j)
    			  if(i^j) printf(" %d",j);
    			printf("\n"),fflush(stdout);
    			in();res=in();
    			if(m1==-1) m1=res,++n1;
    			else if(res==m1) ++n1;
    			else if(m2==-1) m2=res,++n2;
    			else ++n2;
    		}
    		if(m1<m2) swap(m1,m2),swap(n1,n2);
    		printf("! %d\n",n1);fflush(stdout);
    	return 0;
    }

\({\frak{E. Divide Points}}\)

对点\((x,y)\)的奇偶性进行讨论,共有\(4\)个集合,易证若其中两个集合非空,则可构造出分类。否则将\((x,y)\)转化为\({(x/2,y/2)}\)再循环。

*赛场上思路局限于建图,并未注意到距离相等的条件苛刻。

\({\frak{code:}}\)

    #include<bits/stdc++.h>
    #define IL inline
    using namespace std;
    const int N=1e3+3;
    int n,a[N],b[N],num[2][2],ans[N];
    IL int in(){
    	char c;int f=1;
    	while((c=getchar())<'0'||c>'9')
    	  if(c=='-') f=-1;
    	int x=c-'0';
    	while((c=getchar())>='0'&&c<='9')
    	  x=x*10+c-'0';
    	return x*f;
    }
    IL void pre(){memset(num,0,sizeof(num));}
    int main()
    {
    	int x,y;n=in();
    	for(int i=1;i<=n;++i) a[i]=in(),b[i]=in();
    	while(1){
    		pre();
    		for(int i=1;i<=n;++i) ++num[a[i]&1][b[i]&1];
    		if((!num[0][0]+!num[0][1]+!num[1][0]+!num[1][1])<=2){
    			if((!!num[0][0]|!!num[1][1])&&(!!num[1][0]|!!num[0][1])){
    				for(int i=1;i<=n;++i) if(a[i]+b[i]&1) ans[++ans[0]]=i;
    			}
    			else if(!!num[0][0]){
    				for(int i=1;i<=n;++i) if((a[i]&1)&&(b[i]&1)) ans[++ans[0]]=i;
    			}
    			else for(int i=1;i<=n;++i) if((a[i]&1)&&!(b[i]&1)) ans[++ans[0]]=i;
    			printf("%d\n",ans[0]);for(int i=1;i<=ans[0];++i) printf("%d ",ans[i]);
    			puts("");return 0;
    		} 
    		for(int i=1;i<=n;++i) a[i]=a[i]>>1,b[i]=b[i]>>1;
    	}
    	return 0;
    }

\({\frak{*F. Awesome Substrings}}\)

一道类似的题

先求出前缀和\(pre\),答案为\(\sum\limits_{i=1}^{n}{\sum\limits_{j=i}^{n}{\left[\left(pre_j-pre_{i-1}\right)k =j-i+1 \right]}},k\in{N^*}。\)

我们对\(k\)进行划分,对\(k \leq T\)则用桶在\(O(nT)\)的时间复杂度下求出答案数。

对于\(k>T\),枚举左端点,每增加\(1\)便至少向右扩展\(T+1\)个点,故时间复杂度为\(O(n\cdot\frac{n}{T})。\)

因为计算\(k>T\)的常数更小,所以取\(T<\sqrt{n}\),实测\(T\)\(300\)时可在\(2s\)内通过。

\({\frak{code:}}\)

    #include<bits/stdc++.h>
    #define IL inline
    #define LL long long
    using namespace std;
    const int N=2e5+3,M=300;
    int n,num,buk[N*M+N],pos[N],pre[N];
    char s[N];
    LL ans;
    int main()
    {
      scanf("%s",s+1);
      n=strlen(s+1);
      for(int i=1;i<=n;++i) pre[i]=pre[i-1]+s[i]-'0';
      for(int i=1;i<=n;++i) if(s[i]=='1') pos[++num]=i;pos[++num]=n+1;
      for(int i=1;i<=M;++i){
      	++buk[i*n];
      	for(int j=1;j<=n;++j){
      		int val=j+i*(n-pre[j]);
      		ans+=buk[val],++buk[val];
    		}
    		--buk[i*n];
    		for(int j=1;j<=n;++j) --buk[j+i*(n-pre[j])];
    	}
    	for(int i=0;i<n;++i){
    		for(int j=1;j+pre[i]+1<=num;++j){
    			int l=max(pos[pre[i]+j],j*(M+1)+i),r=pos[pre[i]+j+1]-i-1;
    			if(l>n) break;l-=i;
    			if(l<=r) ans+=r/j-(l-1)/j;
    		}
    	}
    	printf("%I64d\n",ans);
    	return 0;
    }

\({\frak{G. Subset with Zero Sum}}\)

显然,\(1 \leq i-a_i \leq n\),所以\(\forall i \in [1,n]\)\(i-a_i\)连一条边,则必然存在一个环。

这个环体现以下等式:

\(i_1-a_{i_1}=i_2\)

\(i_2-a_{i_2}=i_3\)

\(\vdots\)

\(i_n-a_{i_n}=i_1\)

等式相加,得\(\sum\limits_{k=1}^n a_{i_k} = 0。\)

注意回溯的处理。

\({\frak{code:}}\)

    #include<bits/stdc++.h>
    #define IL inline
    using namespace std;
    const int N=1e6+3;
    int n,fa[N],ans[N],vis[N];
    IL int in(){
    	char c;int f=1;
    	while((c=getchar())<'0'||c>'9')
    	  if(c=='-') f=-1;
    	int x=c-'0';
    	while((c=getchar())>='0'&&c<='9')
    	  x=x*10+c-'0';
    	return x*f;
    }
    void dfs(int u){
    	if(vis[u]){
    		int v=u;ans[++ans[0]]=u,u=fa[u];
    		while(u^v) ans[++ans[0]]=u,u=fa[u];
    		return;
    	}
    	vis[u]=1,dfs(fa[u]),vis[u]=0;
    }
    int main()
    {
    	int t=in();
    	while(t--){
    		n=in(),ans[0]=0;
    		for(int i=1;i<=n;++i) fa[i]=i-in();
    		dfs(1);printf("%d\n",ans[0]);
    		for(int i=1;i<=ans[0];++i) printf("%d ",ans[i]);puts("");
    	}
    	return 0;
    }
posted @ 2019-12-31 23:51  (o-ωq)).oO  阅读(233)  评论(0编辑  收藏  举报