Codeforces Round #649 (Div.2) Solution

前言

太久没打,手速/脑力都不行啦~~

A A

  • x ∤ s u m , a n s = n x\not| sum,ans=n
  •    x a i , a n s = 1 \forall~~ x|a_i,ans=-1
  • 否则,去掉前缀/后缀

int n,m,l,r,ans;
ll s;

int main() {
	int _;qr(_); while(_--) {
		qr(n); qr(m); l=r=ans=-1; s=0;
		for(int i=1,x;i<=n;i++) {
			qr(x);
			if(x%m) {
				s+=x;
				if(l==-1) l=i;
				r=i;
			}
		}
		if(s%m) pr2(n);
		else if(l==-1) puts("-1");
		else pr2(n-min(l,n-r+1));
	}
	return 0;
}

B B

p i p_i 是一个峰值,则保留.

int n,p[N],f[N],cnt;

int main() {
	int _;qr(_); while(_--) {
		qr(n); 
		for(int i=1;i<=n;i++) qr(p[i]);
		f[cnt=1]=p[1];
		for(int pre=1,i=2;i<n;i++) {
			if((p[i]>p[pre])^(p[i+1]>p[i]))f[++cnt]=p[i],pre=i;
		}
		f[++cnt]=p[n]; pr2(cnt);
		for(int i=1;i<=cnt;i++) pr1(f[i]);
		puts("");
	}
	return 0;
}

C C

0 a i i , a i a i + 1 \because 0\le a_i\le i,a_i\le a_{i+1}
a n s 1 \therefore ans\ne -1 .
i i 个数一定能构造出答案 a i a_i .
我们用一个队列维护一下还未取值的点,在 a i a_i 发生变化的时候倒序插入即可.

int n,a[N],m=1e6,q[N],l=1,r,f[N];

int main() {
	qr(n); 
	for(int i=1;i<=n;i++) 
		qr(a[i]);
	int cnt=0;
	for(int i=1;i<=n;i++) {
		q[++r]=i; cnt++;
		if(a[i]^a[i-1]) {
			int x=a[i],y=a[i-1];
			while(cnt&&x>y+1) f[q[l++]]=--x,cnt--;
			f[q[r--]]=y; cnt--;
			if(cnt<0) puts("-1"),exit(0);
		}
	}
	while(cnt) f[q[l++]]=m,cnt--;
	for(int i=1;i<=n;i++) pr1(f[i]);
	return 0;
}

D D

如果是一棵树,那么用黑白染色,然后取较大的集合一定能解决 Q 1 Q1 .
否则,找到一个简单环也一定能求解.
设环的大小为 c n t cnt .

  • c n t > k cnt>k ,输出环.
  • c n t k cnt\le k ,隔着输出 c e i l ( k / 2 ) ceil(k/2) 个数即可.
#include<map>
#include<set>
#include<ctime>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define lc (x<<1)
#define rc (x<<1|1)
#define gc getchar()//(p1==p2&&(p2=(p1=buf)+fread(buf,1,size,stdin),p1==p2)?EOF:*p1++)
#define mk make_pair
#define pi pair<int,int>
#define pb push_back
#define IT iterator
#define SZ(a) ((int)a.size())
#define all(a) a.begin(),a.end()
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int N=1e5+10,size=1<<20,mod=998244353;

//char buf[size],*p1=buf,*p2=buf;
template<class o> void qr(o &x) {
	char c=gc; x=0; int f=1;
	while(!isdigit(c)){if(c=='-')f=-1; c=gc;}
	while(isdigit(c)) x=x*10+c-'0',c=gc;
	x*=f;
}
template<class o> void qw(o x) {
	if(x/10) qw(x/10);
	putchar(x%10+'0');
}
template<class o> void pr1(o x) {
	if(x<0)x=-x,putchar('-');
	qw(x); putchar(' ');
}
template<class o> void pr2(o x) {
	if(x<0)x=-x,putchar('-');
	qw(x); puts("");
}

int n,m,q,pos[N],sta[N],top,cir[N],cnt;
vector<int> e[N],col[2];
void add(int x,int y) {e[x].push_back(y);}

bool dfs(int x) {
	sta[++top]=x; pos[x]=top; col[top&1].push_back(x);
	int low=-1;
	for(int y:e[x])
		if(pos[y]&&top-pos[y]>1) low=max(low,pos[y]);//找一个简单环.中间一定没有边(否则前面就已经找到环了) 
	if(~low) {
		for(int i=low;i<=top;i++)
			cir[++cnt]=sta[i];
		return 1;
	}
	for(int y:e[x])
		if(!pos[y]&&dfs(y)) return 1;
	top--;return 0;
}

int main() {
	qr(n); qr(m); qr(q);
	for(int i=1,x,y;i<=m;i++) {
		qr(x); qr(y);
		add(x,y); add(y,x);
	}
	dfs(1);
	if(cnt) {//如果找到环,那么一定有解 
		if(cnt<=q) {
			puts("2");pr2(cnt);
			while(cnt) 
				pr1(cir[cnt--]);
		}
		else {
			puts("1");
			for(int i=1;i<=q;i+=2)
				pr1(cir[i]);
		}
	}
	else {
		puts("1");
		q=(q-1)/2+1;
		int p=(col[0].size()<col[1].size()),c=0;
		for(auto i:col[p]) {
			pr1(i);
			if(++c==q) break;
		}
	}
	return 0;
}



E E

注释讲得较清楚了吧…

看完代码后你可能觉得这个代码可能会出现询问 3 n 3n 次的疑问.(即前面找含0的二元组 2 n 2n 次,最后求解 n n 次.中间部分你可以认为 100 100 次一定能求解,所以不用管它)

for(int i=3;i<=n;i++) {
	int j=ask(y,i);
	if(z>j) x=i,z=j;//x此时一定不为0 
	else if(z==j) y=i,z=ask(x,y);//y此时一定不为0.(反证法) 
}

你可能认为if(z==j) y=i,z=ask(x,y);的运行次数为 n n .
其实不然, a s k ( x , y ) = = a s k ( y , i ) ask(x,y)==ask(y,i) 当且仅当 p x , p i p y p_x,p_i 为p_y 的真子集,所以 p y p i p_y\rightarrow p_i 那么二进制下一的个数不断减小,次数至多为 log n \log n .所以大可不必担心…

#include<map>
#include<set>
#include<ctime>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define lc (x<<1)
#define rc (x<<1|1)
#define gc getchar()//(p1==p2&&(p2=(p1=buf)+fread(buf,1,size,stdin),p1==p2)?EOF:*p1++)
#define mk make_pair
#define pi pair<int,int>
#define pb push_back
#define IT iterator
#define SZ(a) ((int)a.size())
#define all(a) a.begin(),a.end()
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int N=1<<11|10,size=1<<20,mod=998244353;

//char buf[size],*p1=buf,*p2=buf;
template<class o> void qr(o &x) {
	char c=gc; x=0; int f=1;
	while(!isdigit(c)){if(c=='-')f=-1; c=gc;}
	while(isdigit(c)) x=x*10+c-'0',c=gc;
	x*=f;
}
template<class o> void qw(o x) {
	if(x/10) qw(x/10);
	putchar(x%10+'0');
}
template<class o> void pr1(o x) {
	if(x<0)x=-x,putchar('-');
	qw(x); putchar(' ');
}
template<class o> void pr2(o x) {
	if(x<0)x=-x,putchar('-');
	qw(x); puts("");
}

int n,x,y,z,vis[N],ans[N];

map<pi,int> s;

int ask(int x,int y) {
	if(x>y) swap(x,y);
	pi t=mk(x,y);
	if(s.count(t)) return s[t];
	printf("? %d %d\n",x,y); fflush(stdout);
	qr(x); if(x==-1) exit(0);
	return s[t]=x;
}

int main() {
	srand(time(0));
	qr(n); x=1; y=2; z=ask(x,y);
	//此算法的重点是找到0.找到0后,我们与每个位置|一下即可得到每个位置的答案 
	//我们要让 x,y 中存在0. 
	for(int i=3;i<=n;i++) {
		int j=ask(y,i);
		if(z>j) x=i,z=j;//x此时一定不为0 
		else if(z==j) y=i,z=ask(x,y);//y此时一定不为0.(反证法) 
	}
	//此时我们要确定那个是0.
	int zero=0;
	while(!zero) {
		int t=rand()%n+1;
		if(t==x||t==y) continue;
		if(ask(t,x)<ask(t,y)) zero=x;
		else if(ask(t,x)>ask(t,y)) zero=y;
		//设x|y=k,则当k为t的真子集时,ask(t,x)==ask(t,y).
		//当k为二的次幂时,相等的次数最多.但是不相等的概率依然有0.5.
		//所以,很快即可得到答案.(100次都找不到的概率=1-(0.5)^100,所以不会那么背吧...) 
	}
	for(int i=1;i<=n;i++) {
		if(i==zero) ans[i]=0;
		else ans[i]=ask(i,zero);
	}
	printf("! ");
	for(int i=1;i<=n;i++) pr1(ans[i]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42886072/article/details/106744320