CF1991

A. Maximize the Last Element


很明显只有奇数项可以留到最后,所以取奇数项的max即可

#include<bits/stdc++.h>
using namespace std;
int t,n,a[105];
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		for(int i=1;i<=n;i++)scanf("%d",&a[i]);
		int res=0;
		for(int i=1;i<=n;i+=2)res=max(res,a[i]);
		printf("%d\n",res);
	}
	return 0;
}

B. AND Reconstruction


看到位运算先考虑按位做,如果 \(b_i\) 的某一位为 \(1\) , 那么 \(a_i\)\(a_{i+1}\) 的那一位都为 \(1\) 其他位为 \(0\) 即可

最后检验一遍是否符合

#include<bits/stdc++.h>
using namespace std;
int t,n,a[100005],b[100005];
bool vis[100005];
void init(){
	for(int i=1;i<=n;i++)a[i]=0;
}
bool check(){
	for(int i=1;i<n;i++)
		if((a[i]&a[i+1])!=b[i])
			return 1;
	return 0;
}
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		for(int i=1;i<n;i++)scanf("%d",&b[i]);
		for(int i=0;i<30;i++){
			for(int j=1;j<n;j++)
				if((b[j]>>i)&1)
					vis[j]=vis[j+1]=1;
			for(int j=1;j<=n;j++){
				if(vis[j])a[j]^=(1<<i);
				vis[j]=0;
			}
		}
		if(check())puts("-1");
		else{
			for(int i=1;i<=n;i++)printf("%d ",a[i]);
			puts("");
		}
		init();
	}
	return 0;
}

C. Absolute Zero


直接每次 \(x=(mx+mn)/2\) 就行

这样每次操作以后极差都/2

#include<bits/stdc++.h>
using namespace std;
int t,n,a[200005],res[45],tot;
bool check(){
	for(int i=1;i<=n;i++)
		if(a[i])
			return 0;
	return 1;
}
int main(){
	scanf("%d",&t);
	while(t--){
		tot=0;
		scanf("%d",&n);
		for(int i=1;i<=n;i++)scanf("%d",&a[i]);
		for(int i=1;i<=40;i++){
			sort(a+1,a+1+n);
			int x=(a[1]+a[n])/2;
			for(int i=1;i<=n;i++)a[i]=abs(a[i]-x);
			res[++tot]=x;
			if(check())break;
		}
		if(check()){
			printf("%d\n",tot);
			for(int i=1;i<=tot;i++)printf("%d ",res[i]);
			puts("");
		}else puts("-1");
	}
	return 0;
}

D. Prime XOR Coloring


一开始看到一堆人秒过直接交了个 \(n/2+1\) , 唐死了

根据样例后面至少分4个颜色

所以按照mod4的余数分个类就行,这样同种颜色异或结果总会是4的倍数

#include<bits/stdc++.h>
using namespace std;
int t,n;
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		if(n==1)puts("1\n1");
		else if(n==2)puts("2\n1 2");
		else if(n==3)puts("2\n1 2 2");
		else if(n==4)puts("3\n1 2 2 3");
		else if(n==5)puts("3\n1 2 2 3 3");
		else{
			printf("%d\n",4);
			for(int i=1;i<=n;i++)printf("%d ",i%4+1);
			puts("");
		}
	}
	return 0;
}

E. Coloring Game


首先发现如果不是二分图那么Alice之需要不停给出 \(1 2\) 即可

那么猜测在是二分图时选Bob,不是二分图时选Alice

思考Bob如何必胜

将二分图分为两堆,对于Alice给出的任意提问,优先考虑1仍在第一堆,2扔在第二堆,如果一堆满了,就把两种颜色的另一个扔在另一堆

比如当第一堆满了时,Alice给出 \(1 3\) ,那么就将3扔到第二堆

#include<bits/stdc++.h>
using namespace std;
int t,n,m;
struct edge{
	int v,nx;
}e[20005];
int cnt,hd[10005];
void add(int u,int v){
	e[++cnt]=edge{v,hd[u]};
	hd[u]=cnt;
}
bool vis;
int col[10005];
queue<int> que[2];
void init(){
	vis=1;
	memset(hd,0,sizeof(hd));
	memset(e,0,sizeof(e));
	memset(col,0,sizeof(col));
}
void dfs(int u){
	for(int i=hd[u];i;i=e[i].nx){
		int v=e[i].v;
		if(col[v]){
			if(col[v]==col[u])vis=0;
			continue;
		}
		col[v]=3-col[u];
		dfs(v);
	}
}
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&m);
		init();
		for(int i=1;i<=m;i++){
			int u,v;scanf("%d%d",&u,&v);
			add(u,v);add(v,u); 
		}
		for(int i=1;i<=n;i++)
			if(!col[i]){
				col[i]=1;
				dfs(i);
			}
		if(!vis){
			cout<<"Alice"<<endl;cout.flush();
			for(int i=1;i<=n;i++){
				cout<<"1 2"<<endl;
				int u,v;scanf("%d%d",&u,&v);
				cout.flush();
			}
		}else{
			for(int i=1;i<=n;i++)que[col[i]-1].push(i);
			cout<<"Bob"<<endl;cout.flush();
			for(int i=1;i<=n;i++){
				int c1,c2;scanf("%d%d",&c1,&c2);
				if(c1>c2)swap(c1,c2);
				if(c1==2 && c2==3){
					if(!que[0].empty())cout<<que[0].front()<<" "<<c1<<endl,que[0].pop();
					else if(!que[1].empty())cout<<que[1].front()<<" "<<c2<<endl,que[1].pop();
				}else if(c1==1 && c2==3){
					if(!que[1].empty())cout<<que[1].front()<<" "<<c2<<endl,que[1].pop();
					else if(!que[0].empty())cout<<que[0].front()<<" "<<c1<<endl,que[0].pop();
				}else if(c1==1 && c2==2){
					if(!que[0].empty())cout<<que[0].front()<<" "<<c2<<endl,que[0].pop();
					else if(!que[1].empty())cout<<que[1].front()<<" "<<c1<<endl,que[1].pop();
				}
				cout.flush();
			}
		}
	}
	return 0;
}

F. Triangle Formation


先思考如果只需求一个三角形时

正面比较难,所以该为研究什么情况下不存在三角形

\(a\) 从小到大排列

可以得出 \(a_{i+2} >= a{i+1} + a{i}\)

此时 \(a\) 将构成一个类似斐波那契数列的东西

可以得出在第45项 \(a_45 >= 1e9\)

所以如果询问区间大于45,就必定有一个三角形

那么如果需要求两个,那么对于一个长度超过48的区间

先将其中组成三角形的三个删去,剩余45个必然组成三角形

所以可得只要区间>=48就必定存在两个三角形

接下来考虑区间<=48的

只需要找第一个和最后一个连续3个组成三角形的边

判断他们是否重复,不重复则找到了两个三角形

然后在找连续6个边,考虑这6个边的所有分组情况是否存在组成两个三角形的

这样可以判定所有情况

大致证明:如果存在一种组成两个三角形的方法,不满足以上两条,那么一定可以将每个三角形的短边下标增大,或者长边下标减小,肯定更优,这样最后会贴到一起

#include<bits/stdc++.h>
using namespace std;
#define mid (l+r>>1)
#define ls (rt<<1)
#define rs (rt<<1|1)
#define pii pair<int,int>
#define fi first
#define se second
#define mp make_pair
int n,q,a[100005];
int b[155];
bool check(int l,int r){
	if(r-l+1>=150)return 1;
	int len=r-l+1;
	for(int i=1;i<=len;i++)b[i]=a[l+i-1];
	sort(b+1,b+1+len);
	int loc1=0,loc2=0;
	for(int i=1;i<=len-2;i++)
		if(b[i]+b[i+1]>b[i+2]){
			loc1=i;
			break;
		}
	for(int i=len;i>=3;i--)
		if(b[i-2]+b[i-1]>b[i]){
			loc2=i-2;
			break;
		}
	if(loc1 && loc2 && loc1+3<=loc2)return 1;
	for(int i=1;i<=len-5;i++){
		int u=b[i],v=b[i+1],w=b[i+2],x=b[i+3],y=b[i+4],z=b[i+5];
		if(u+v>w && x+y>z)return 1;
		if(u+v>x && w+y>z)return 1;
		if(u+v>y && w+x>z)return 1;
		if(u+v>z && w+x>y)return 1;
		if(u+w>x && v+y>z)return 1;
		if(u+w>y && v+x>z)return 1;
		if(u+w>z && v+x>y)return 1;
		if(u+x>y && v+w>z)return 1;
		if(u+x>z && v+w>y)return 1;
		if(u+y>z && v+w>x)return 1;
	}
	return 0;
}
int main(){
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	for(int i=1;i<=q;i++){
		int l,r;scanf("%d%d",&l,&r);
		if(check(l,r))puts("YES");
		else puts("NO");
	}
	return 0;
}

赛时为了稳直接做了150个的

posted @ 2024-07-29 15:33  Kent530  阅读(67)  评论(0)    收藏  举报