CodeForces 1328

当你心情不好的时候 vp 一场 div3 就好了。

然后去年 10.1 我好像 AK 了人生中第一场 div. 3 来着。

CF 比赛页面传送门

A - Divisibility Problem

sbt。

#include<bits/stdc++.h>
using namespace std;
void mian(){
	int a,b;
	cin>>a>>b;
	cout<<(a%b?b-a%b:0)<<"
";
}
int main(){
	int testnum=1;
	cin>>testnum;
	while(testnum--)mian();
	return 0;
}

B - K-th Beautiful String

直接枚举是平方的,考虑枚举左边的一个 ( exttt b) 的位置,然后看当前有多少个,累加一下找到左边 ( exttt b) 的位置就好办了。

#include<bits/stdc++.h>
using namespace std;
void mian(){
	int n,k;
	cin>>n>>k;
	for(int i=n-1;;i--){
		if(n-i>=k){
			for(int j=1;j<i;j++)putchar('a');
			putchar('b');
			for(int j=i+1;j<i+(n-i-k+1);j++)putchar('a');
			putchar('b');
			for(int j=i+(n-i-k+1)+1;j<=n;j++)putchar('a');
			puts("");
			return;
		}
		k-=n-i;
	}
}
int main(){
	int testnum=1;
	cin>>testnum;
	while(testnum--)mian();
	return 0;
}

C - Ternary XOR

直接贪心尽量最小化某一个是错的,因为它问的是 (max) 的最小值而非 (min) 的最小值。

注意到对于任意一个前缀,如果它里面不包含 (1),那么根据平均主义的贪心肯定都是两个数的每位都是除以 (2)。于是找到第一个 (1),显然只能分成一个 (0) 一个 (1),然后此时铁定 (1) 的那个更大了,以后就极力培养它(令以后它的所有位都是 (0))。

#include<bits/stdc++.h>
using namespace std;
void mian(){
	int n;
	string a,b,c;
	cin>>n>>a;
	for(int i=0;i<n;i++)if(a[i]=='1'){
		for(int j=0;j<i;j++){
			if(a[j]=='0')b+='0',c+='0';
			else b+='1',c+='1';
		}
		b+='1',c+='0';
		for(int j=i+1;j<n;j++){
			if(a[j]=='0')b+='0',c+='0';
			else if(a[j]=='1')b+='0',c+='1';
			else b+='0',c+='2';
		}
		cout<<b<<"
"<<c<<"
";
		return;
	}
	for(int j=0;j<n;j++){
		if(a[j]=='0')b+='0',c+='0';
		else b+='1',c+='1';
	}
	cout<<b<<"
"<<c<<"
";
}
int main(){
	int testnum=1;
	cin>>testnum;
	while(testnum--)mian();
	return 0;
}

先用 (1,2) 两个颜色贪心,相邻两个动物相同则同,不同则异。然后检查 (1)(n) 是否符合。

如果符合直接输出。如果不符合,考虑将贪心过程中某个相同的相邻对取个反使得 (1)(n) 不同然后输出;如果没有相同相邻对就是 (3)

#include<bits/stdc++.h>
using namespace std;
const int N=200000;
int a[N+1];
int ans[N+1];
void mian(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)scanf("%d",a+i);
	ans[1]=1;
	for(int i=2;i<=n;i++)
		if(a[i]==a[i-1])ans[i]=ans[i-1];
		else ans[i]=3-ans[i-1];
	int mx=0;
	for(int i=1;i<=n;i++)mx=max(mx,ans[i]);
	if(a[1]!=a[n]&&ans[1]==ans[n]){
		bool used=false;
		for(int i=2;i<=n;i++)
			if(a[i]==a[i-1])
				if(!used)ans[i]=3-ans[i-1],used=true;
				else ans[i]=ans[i-1];
			else ans[i]=3-ans[i-1];
		if(a[1]!=a[n]&&ans[1]==ans[n]){
			cout<<mx+1<<"
";
			ans[1]=mx+1;
			for(int i=1;i<=n;i++)printf("%d ",ans[i]);
			puts("");
		}
		else{
			cout<<mx<<"
";
			for(int i=1;i<=n;i++)printf("%d ",ans[i]);
			puts("");
		}
	}
	else{
		cout<<mx<<"
";
		for(int i=1;i<=n;i++)printf("%d ",ans[i]);
		puts("");
	}
}
int main(){
	int testnum=1;
	cin>>testnum;
	while(testnum--)mian();
	return 0;
}

E - Tree Queries

结论:( exttt{YES}) 当且仅当所有节点的爸爸在同一条链上。

充分性证明:连那条同链即可。

必要性证明:若否,即存在一对不互为祖先与后代的爸爸,那最亲近最亲近也只能是兄弟了,然后发现也是不行的。

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
const int N=200000;
int n,qu;
vector<int> nei[N+1];
int fa[N+1],dep[N+1];
int dfn[N+1],nowdfn,mxdfn[N+1];
void dfs(int x=1){
	dfn[x]=mxdfn[x]=++nowdfn;
	for(int i=0;i<nei[x].size();i++){
		int y=nei[x][i];
		if(y==fa[x])continue;
		fa[y]=x;
		dep[y]=dep[x]+1;
		dfs(y);
		mxdfn[x]=mxdfn[y];
	}
}
int cmp(int x,int y){return dep[x]<dep[y];}
void mian(){
	cin>>n>>qu;
	for(int i=1;i<n;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		nei[x].pb(y);nei[y].pb(x);
	}
	dfs();
	while(qu--){
		int m;
		scanf("%d",&m);
		vector<int> v;
		for(int i=1;i<=m;i++){
			int x;
			scanf("%d",&x);
			v.pb(max(1,fa[x]));
		}
		sort(v.begin(),v.end(),cmp);
		bool flg=true;
		for(int i=0;i+1<v.size();i++)flg&=dfn[v[i]]<=dfn[v[i+1]]&&dfn[v[i+1]]<=mxdfn[v[i]];
		puts(flg?"YES":"NO");
	}
}
int main(){
	int testnum=1;
//	cin>>testnum;
	while(testnum--)mian();
	return 0;
}

F - Make k Equal

有个结论,最优情况一定是从左端和右端分别向中间靠拢,最终聚到一个原本在数组中出现的数上。

那么就枚举这个数。分成三种情况:只有左边往右靠拢、只有右边往左靠拢、两边都考虑。前两种随便搞吧;后面一种的话注意到两边分别的靠拢过程中倒数第二步之前都是必须要做的,然后最后一步的操作步数和也是确定的,那就预处理一下就可以随便做了吧。

WA 了几发,疑神疑鬼,代码可能有些奇怪?

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define int long long
const int inf=0x3f3f3f3f3f3f3f3f;
const int N=1000000;
int n,m;
int a[N+1];
vector<int> nums;
int cnt[N+1];
int d[N+1];
void discrete(){
	sort(nums.begin(),nums.end());
	nums.resize(unique(nums.begin(),nums.end())-nums.begin());
	while(nums.size()<n)nums.pb(nums.back()+1);
	for(int i=1;i<=n;i++)a[i]=lower_bound(nums.begin(),nums.end(),a[i])-nums.begin(),cnt[a[i]+1]++;
	for(int i=1;i<n;i++)d[i]=nums[i]-nums[i-1];
}
int Cnt[N+1],cnT[N+1];
int Tim[N+1],tiM[N+1];
void mian(){
	cin>>n>>m;
	for(int i=1;i<=n;i++)scanf("%lld",a+i),nums.pb(a[i]);
	discrete();
	for(int i=1;i<=n;i++)Cnt[i]=Cnt[i-1]+cnt[i];
	for(int i=n;i;i--)cnT[i]=cnT[i+1]+cnt[i];
	for(int i=2;i<=n;i++)Tim[i]=Tim[i-1]+Cnt[i-2]+Cnt[i-1]*(d[i-1]-1);
	for(int i=n-1;i;i--)tiM[i]=tiM[i+1]+cnT[i+2]+cnT[i+1]*(d[i]-1);
	int ans=inf;
	for(int i=1;i<=n;i++)
		if(m<=cnt[i])ans=0;
		else{
			if(Cnt[i-1]>=m-cnt[i])ans=min(ans,Tim[i]+m-cnt[i]);
			if(cnT[i+1]>=m-cnt[i])ans=min(ans,tiM[i]+m-cnt[i]);
			ans=min(ans,Tim[i]+tiM[i]+m-cnt[i]);
		}
	cout<<ans;
}
signed main(){
	int testnum=1;
//	cin>>testnum;
	while(testnum--)mian();
	return 0;
}
原文地址:https://www.cnblogs.com/ycx-akioi/p/CodeForces-1328.html