Codeforces Round #669 (Div. 2)

A
https://codeforces.com/contest/1407/problem/A
判断一下,直接输出合适个数的 全0 或 全1 即可。

#include <cstdio>
int t,n,a[5000],c[5];

int main(){
	scanf("%d",&t);
	while (t--){
		c[0]=c[1]=0;
		scanf("%d",&n);
		for (int i=1; i<=n; i++){
			scanf("%d",&a[i]);
			c[a[i]]++;
		}
		if (c[0]>=n/2){
			printf("%d\n",c[0]);
			for (int i=1; i<=c[0]; i++) printf("0 ");
			printf("\n");
		}
		if (c[1]>n/2){
			if (c[1]%2) c[1]--;
			printf("%d\n",c[1]);
			for (int i=1; i<=c[1]; i++) printf("1 ");
			printf("\n");
		}
	}
}

B
https://codeforces.com/contest/1407/problem/B
数据比较小,允许 nnlogn,那么先排序,当然最大的先选,然后后面的每次扫一遍GCD选出最大的即可。GCD=1时就可以随便把剩下的数出来了。

#include <cstdio>
#include <algorithm>
using namespace std;
int n,t,a[2000],b[2000],c[2000],lgg,gg,cnt,tmp1,tmp2;

int GCD(int b,int c){return c ? GCD(c,b%c) : b;}

int main(){
	scanf("%d",&t);
	while (t--){
		scanf("%d",&n);
		for (int i=1; i<=n; i++) scanf("%d",&a[i]),c[i]=1;
		sort(a+1,a+n+1);
		lgg=b[cnt=1]=a[n];
		c[n]=0;
		while (lgg>1 && cnt<n){
			gg=0;
			cnt++;
			for (int i=1; i<=n; i++) if(c[i]){
				tmp1=GCD(lgg,a[i]);
				if (tmp1>gg) gg=tmp1,b[cnt]=a[i],tmp2=i;
			}
			c[tmp2]=0;
			lgg=gg;
		}
		for (int i=1; i<=n; i++) if (c[i]) b[++cnt]=a[i];
		for (int i=1; i<=n; i++) printf("%d ",b[i]);
		
		printf("\n");
		for (int i=1; i<=n; i++) b[i]=0;
	}
}

C
https://codeforces.com/contest/1407/problem/C
首先发现一个特点, i j两个位反向询问之后,就能得出更小的那个的值,而且另一个就是更大的一个不知道的值。
那么可以从左往右,每次反向询问之前找到最大的和下一个数i,2(n-1) 次询问就能得出 n-1 个“小的”数,此时剩下那一个就是最大的n了。

#include <cstdio>
int n,mx,x,y,p[20000];

int main(){
	scanf("%d",&n);
	mx=1;
	for (int i=2; i<=n; i++){
		printf("? %d %d\n",mx,i);
		fflush(stdout);
		scanf("%d",&x);
		printf("? %d %d\n",i,mx);
		fflush(stdout);
		scanf("%d",&y);
		if (x<y){
			p[i]=y;
		}
		else{
			p[mx]=x;
			mx=i;
		}
	}
	p[mx]=n;
	printf("! ");
		for (int i=1; i<=n; i++) printf("%d ",p[i]);
}

D
https://codeforces.com/contest/1407/problem/D
利用单调栈分别求出每个位置 往左/往右 的第一个 不比它小/大 的位置,之后动态规划即可。
dp[i] 代表从 1 到 i 的最小步数,从 2 开始往右求,利用前面求出的,把 i 能一步跳到的地方遍历一遍更新 dp值 即可。

#include <cstdio>
#define Add(x,y) nxt[0][++cnt]=(y),nxt[1][cnt]=A[x],A[x]=cnt
#define For(x) for(int kk=A[x],v=nxt[0][kk]; kk; kk=nxt[1][kk],v=nxt[0][kk])
int n,a[500000],dp[500000];
int st[500000],top;
int A[500000],nxt[2][20000000],cnt;

int main(){
	scanf("%d",&n);
	for (int i=1; i<=n; i++) scanf("%d", &a[i]);
	
	top=0;
	st[0]=0;
	for (int i=1; i<=n; i++){
		while (a[st[top]]<a[i] && top) top--;
		Add(i,st[top]);
		st[++top]=i;
	}
	
	top=0;
	st[0]=0;
	for (int i=1; i<=n; i++){
		while (a[st[top]]>a[i] && top) top--;
		Add(i,st[top]);
		st[++top]=i;
	}
	
	top=0;
	st[0]=0;
	for (int i=n; i; i--){
		while (a[st[top]]<a[i] && top) top--;
		Add(st[top],i);
		st[++top]=i;
	}
	
	top=0;
	st[0]=0;
	for (int i=n; i; i--){
		while (a[st[top]]>a[i] && top) top--;
		Add(st[top],i);
		st[++top]=i;
	}
	
	/*
	for (int i=2; i<=n; i++){
		printf("[%d]\t",i);
		For(i) printf("%d ",v);
		printf("\n");
	}
	*/
	
	
	//dp[i]: 走到 i 最少步数
	for (int i=1; i<=n; i++) dp[i]=2147483647;
	dp[1]=0;
	for (int i=2; i<=n; i++){
		For(i) if (v){
			if (dp[v]+1<dp[i]) dp[i]=dp[v]+1;
		}
	}
	printf("%d",dp[n]);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值