Codeforces Round #696 (Div. 2)

3 篇文章 0 订阅

A

 

这道题目是很明显的贪心,因为位数多的数字一定更大,所以我们可以记录前一位数字,通过当前位置的配对,尽量保证和上一位不同

 

代码

#include<bits/stdc++.h>
using namespace std;
int n;
int main()
{
//	freopen("a.in","r",stdin);
//	freopen("a.out","w",stdout);
	int t;scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		char x;
		int dig,last=-1;
		getchar();
		for(int i=1;i<=n;i++)
		{
			scanf("%c",&x);
			dig=x-'0';
			if(dig+1!=last)
			{
				last=dig+1;
				printf("%d",1);
				continue;
			}
			last=dig;
			printf("%d",0);
		}
		printf("\n");	
	}
	return 0;
}

 

B

 

这道题目要求至少有四个因子,并且所有的因子的差大于等于d的最小数

首先所有的数都有因子1,所以第二个因子b大于等于d+1,考虑到按从小到大排序因子,所以这里枚举的因子一定是素数,然后第三个因子c大于等于b+d,第四个因子可以是c*b,可以证明b*c-c大于d,所以就可以得到数字为b*c

 

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+5; 
typedef long long ll;
ll n;
int p[maxn];
int main()
{
	//freopen("a.in","r",stdin);
	//freopen("a.out","w",stdout);
	int t;scanf("%d",&t);
	for(int i=2;i<=maxn;i++)
		if(!p[i])
			for(int j=2*i;j<=maxn;j+=i) p[j]=1;
	while(t--)
	{
		scanf("%lld",&n);
		int p1,p2;
		for(p1=1+n;p[p1];p1++);
		for(p2=p1+n;p[p2];p2++);
		ll ans=1LL*p1*p2;
		printf("%lld\n",ans);	
	}
	return 0;
}

 

C

 

这道题目还是有贪心的思想,首先可以将a排序

我们可以证明,每次都一定要取一个最大的数字,否则,这个数字以后将无法被取走,这样我们就可以在已知上一次的较大值时,计算这次是否可以取到,所以这样我们就可以通过枚举第一次取得较小值,然后一直贪心的取

实现的过程中,有一些小的细节:比如判重,由于这个ai的范围较大,不能每次都赋一次值,所以我用了一个map记录

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e3+5; 
const int N=1e6+5;
typedef long long ll;
int n,a[maxn],xx[maxn],yy[maxn];
int tmp[N];
map <int,int> G; 
int main()
{
	//freopen("a.in","r",stdin);
	//freopen("a.out","w",stdout);
	int t;scanf("%d",&t); 
	while(t--)
	{
		scanf("%d",&n); int maxx=0;
		for(int i=1;i<=2*n;i++) scanf("%d",&a[i]),maxx=max(maxx,a[i]);
		sort(a+1,a+2*n+1);
		for(int i=1;i<=2*n;i++) G[a[i]]++;
		int yes=0;
		for(int i=1;i<2*n;i++)
		{
			for(int j=1;j<=2*n;j++) tmp[a[j]]=G[a[j]];
			int step=0,last=2*n,pos=2*n-1;
			if(pos==i) pos--;
			tmp[a[i]]--; tmp[a[2*n]]--;
			xx[++step]=a[i]; yy[step]=a[n*2];
			while(step<n)
			{
				int dig=a[last]-a[pos];
				tmp[a[pos]]--;
				if(!G[dig] || !tmp[dig] || !pos) break;
				xx[++step]=a[pos];  yy[step]=dig;
				tmp[dig]--;
				last=pos;
				while(!tmp[a[pos]] && pos>=0) pos--;
			}	
			if(step==n) yes=i;
			if(yes) break;
		}	
		if(!yes) printf("NO\n");
		else
		{
			printf("YES\n%d\n",a[yes]+a[2*n]);
			for(int i=1;i<=n;i++)
				printf("%d %d\n",xx[i],yy[i]);
		}
		for(int i=1;i<=2*n;i++) G[a[i]]--;
	}
	return 0;
}

 

D

 

这道题目的思路来自于一定要从最左侧的和最右侧开始取,否则它们将会被剩下,然后,我们可以求两个数组,s和p分别表示从左开始取和从右开始取的第i位剩余的个数,这些可以在O(N)的时间内完成

然后我们可以枚举交换的位置i和i+1,验证pi-1,ai,ai+1,si+2,进行验证即可

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int t,n,a[maxn],s[maxn],p[maxn],b[maxn];
int check(int f[],int cnt)
{
	int e[maxn];
	for(int i=1;i<=cnt;i++) e[i]=f[i];
	for(int i=1;i<cnt;i++)
	{
		if(e[i]>e[i+1]) return 0;
		e[i+1]-=e[i];
		e[i]=0;
	}
	if(!e[cnt]) return 1;
	return 0;
}
int main()
{
//	freopen("a.in","r",stdin);
//	freopen("a.out","w",stdout);
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i];
		if(n==1) {printf("NO\n"); continue;} 
		if(check(a,n)==1) { printf("YES\n"); continue;}
		swap(a[1],a[2]); if(check(a,n)==1) { printf("YES\n"); continue;}
		swap(a[1],a[2]); swap(a[n-1],a[n]); if(check(a,n)==1) { printf("YES\n"); continue;}
		swap(a[n-1],a[n]);
		p[1]=b[1];
		for(int i=2;i<=n;i++)
		{
			if(p[i-1]==-1 || b[i-1]>b[i])
			{
				p[i]=-1;
				continue;
			}
			b[i]-=b[i-1];
			b[i-1]=0;
			p[i]=b[i];
		}
		for(int i=1;i<=n;i++) b[i]=a[i];
		s[n]=b[n];
		for(int i=n-1;i>=1;i--)
		{
			if(s[i+1]==-1 || b[i+1]>b[i])
			{
				s[i]=-1;
				continue;
			}
			b[i]-=b[i+1];
			b[i+1]=0;
			s[i]=b[i];
		}
		int flag=1;
		for(int i=2;i+2<=n;i++)
		{
			int c[5]={0,p[i-1],a[i],a[i+1],s[i+2]};
			if(c[1]==-1 || c[4]==-1) continue;
			swap(c[2],c[3]);
			if(check(c,4)==1) {flag=0; printf("YES\n"); break;}
		}
		if(flag) printf("NO\n");
	}
	return 0;
}

 

E

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值