Codeforces Round #669 (Div. 2)

http://codeforces.com/contest/1407

A. Ahahahahahahahaha

看1多还是0多,n/2说奇数还是偶数分类

#include<bits/stdc++.h>
using namespace std;

int cnt[2];

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

B. Big Vova

n方暴力

#include<bits/stdc++.h>
using namespace std;

const int maxn=1e3+5;
int a[maxn];

bool cmp(int x,int y){
	return x>y;
}

int gcd(int a,int b){
	if(b==0)return a;
	return gcd(b,a%b);
}

int main()
{
	int t,n,now,p,maxa;
	scanf("%d",&t);
	while(t--){
		maxa=0;
		scanf("%d",&n);
		for(int i=1;i<=n;i++)scanf("%d",&a[i]);
		sort(a+1,a+1+n,cmp);
		now=a[1]; 
		for(int i=2;i<=n;i++){
			maxa=0; 
			for(int j=i;j<=n;j++){
				
				int tmp=gcd(now,a[j]);
				if(tmp>maxa)maxa=tmp,p=j;
			}
			now=maxa;
			swap(a[i],a[p]);
		}
		for(int i=1;i<=n;i++)printf("%d ",a[i]); cout<<endl;
	}
	return 0;
}

C. Chocolate Bunny

大致题意:有1到n 的排列,你有至多2*n次询问(? i j 返回a[i]%a[j]的值),请确定这个排列

题解:询问(i,j)和(j,i)就能知道确定a[i],a[j]中较小的一个的值,所以2次可以确定一个

#include<bits/stdc++.h>
using namespace std;

int tmp[10005];

int ask(int x,int y){
	cout<<"?"<<' '<<x<<' '<<y<<endl;
	int k;
	cin>>k;
	return k;
}

int main()
{
	int t,n,a,b;
		scanf("%d",&n);
		int now=1;
		for(int i=2;i<=n;i++){
			a=ask(now,i); b=ask(i,now);
			if(a<b)tmp[i]=b;
			else tmp[now]=a,now=i;
		}
		tmp[now]=n;
		printf("! ");
		for(int i=1;i<=n;i++)printf("%d ",tmp[i]);
		printf("\n");
	
	return 0;
}

D. Discrete Centrifugal Jumps

参考:https://www.cnblogs.com/starve/p/13638360.html

大致题意:

给一个长为n的h,h[i]为第i个的高度,要从1跳到n,每次跳要满足下面的条件之一,问最少的步数

1.i+1=j

2.max(hi+1,…,hj−1)<min(hi,hj)

3.max(hi,hj)<min(hi+1,…,hj−1)

心得:一开式用线段树优化dp,但是这个解法不能得到正确答案

题解:dp+单调队列

1设f[i]为到达 i 的最小步数;

2考虑第二操作为,假设 j 为1~i-1中大于h[i]的最靠右的位置,那么以 j 位置开始的单调递减序列都可以一步转移到 i ,而1~j-1位置的都不能通过操作二来一步跳到 i 位置,因为有 j 位置的“阻拦”

3三同理;

4更新单调队列来维护即可

#include<bits/stdc++.h>
using namespace std;

const int maxn=3e5+5,inf=0x7fffffff;
int n,ti,ta;
int h[maxn],mina[maxn],maxa[maxn],f[maxn];

int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&h[i]),f[i]=inf;
	mina[1]=maxa[1]=1; ti=ta=1;
	f[1]=0;
	for(int i=2;i<=n;i++){
		while(ti&&h[mina[ti]]<h[i])
			f[i]=min(f[i],f[mina[ti--]]+1);
		while(ta&&h[maxa[ta]]>h[i])
			f[i]=min(f[i],f[maxa[ta--]]+1);
		if(ti)f[i]=min(f[i],f[mina[ti]]+1);
		if(ta)f[i]=min(f[i],f[maxa[ta]]+1);
		if(h[mina[ti]]==h[i])ti--;
		if(h[maxa[ta]]==h[i])ta--;
		mina[++ti]=i;
		maxa[++ta]=i;
	}
	cout<<f[n]<<endl;
	return 0;
}

 

E. Egor in the Republic of Dagestan

题意:给一个有向图,每条边有一个类型(0或者1),什么类型的城市就只能走什么类型的边,你需要给每个城市指定类型(0/1),使得从1到n 的最短路最长,甚至长到1无法到达n

题解:spfa

1建反向边

2dis[i][0] dis[i][1] 分别表示i为类型0/1时,从i到n的最短距离(i到n的路径上的城市类型已经指定的情况下)

3对于一条从x到y的边,边的类型为tp, dis[y][tp]=min(dis[y][tp],max(dis[x][0],dis[x][1]))

4输出每个城市的类型——只要枚举每个城市,看dis[i][0]和dis[i][1]哪个大

#include<bits/stdc++.h>
using namespace std;

const int maxn=5e5+5,inf=0x7fffffff-1;
int nxt[maxn],to[maxn],head[maxn],tp[maxn],pre[maxn][2],cl[maxn];
int n,m,cnt;
int dis[maxn][2];
bool inq[maxn];

void add(int x,int y,int k){
	nxt[++cnt]=head[x]; head[x]=cnt; to[cnt]=y; tp[cnt]=k;
}
queue<int>q;

void spfa()
{
	int x,y;
	for(int i=1;i<=n;i++)dis[i][0]=dis[i][1]=inf;
	q.push(n); dis[n][0]=dis[n][1]=0; inq[n]=1; 
	while(!q.empty()){
		x=q.front(); q.pop(); inq[x]=0;
		for(int i=head[x];i;i=nxt[i]){
			y=to[i];
			int tmp=max(dis[x][0],dis[x][1]);//关键 
			if(dis[y][tp[i]]>tmp+1){
				dis[y][tp[i]]=tmp+1; pre[y][tp[i]]=x;
				if(!inq[y])q.push(y),inq[y]=1;
			}
		}
	}
}

int main()
{
	int x,y,k;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&x,&y,&k);
		add(y,x,k);
	}
	spfa();
	int ans=max(dis[1][0],dis[1][1]);
	if(ans==inf)printf("-1\n");
	else printf("%d\n",ans);
//	int now=1;
//	while(now!=n){
//		if(dis[now][0]>dis[now][1])cl[now]=0,now=pre[now][0];
//		else cl[now]=1,now=pre[now][1];
//		if(now==0)break;
//	}
	for(int i=1;i<=n;i++){
		if(dis[i][0]>dis[i][1])printf("0");
		else printf("1");
	}
	return 0;
}
/*
4 7
1 1 0
1 3 1
3 2 0
2 1 0
3 4 1
2 4 0
2 4 1
*/

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值