Codeforces Round #704 (Div. 2)

Codeforces 难得有一次不熬夜的比赛。

比赛链接

官方 Tutorial

A

送分题,记得开 long long。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define int long long
signed main()
{
	int T;
	scanf("%lld",&T);
	while(T--)
	{
		int p,a,b,c;
		scanf("%lld %lld %lld %lld",&p,&a,&b,&c);
		int ta=(p+a-1)/a*a,tb=(p+b-1)/b*b,tc=(p+c-1)/c*c;
		printf("%lld\n",min(min(ta-p,tb-p),tc-p));
	}
	return 0;
}

B

\(\sum\limits_{i = 1}^{n}{n^{n - i} \cdot p_i}\) 可以看作是一个 \(n\) 进制数,所以 \(p_1\) 越大越好,其次是 \(p_2\),以此类推。从 \(n\)\(1\) 枚举,如果当前的数能够安排到前面就安排到前面,按照题意模拟即可。时间复杂度 \(\mathcal O(n)\)(如果实现的好)。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int N=1e5;
int a[N+10],p[N+10]; 
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		int n;
		scanf("%d",&n);
		for(int i=1;i<=n;i++) 
		{
			scanf("%d",&a[i]);
			p[a[i]]=i;
		}
		int pos=n+1;
		vector<int> ans;
		for(int i=n;i;i--)
		{
			for(int j=p[i];j<pos;j++) 
				ans.push_back(a[j]);
			if(p[i]<pos) pos=p[i];
		}
		for(int i=0;(unsigned)i<ans.size();i++) printf("%d ",ans[i]);
		putchar('\n');
	}
	return 0;
}

C

分别对 \(s\) 从前往后和从后往前扫一遍求出 \(pre_i\)\(suf_i\)\(pre_i\) 表示在 \(s\) 中能够满足 \(\forall k\in[1,i],s_{j_k}=t_k\) 的子序列 \(s_{j_1}s_{j_2}\cdots s_{j_i}\)\(1\le j_1<j_2<\cdots< j_i\le n\)) 中最小的 \(j_i\)\(suf_i\) 表示最大的 \(j_i\),答案就是 \(\max\limits_{i=1}^{m-1} \{suf_{i+1}-pre_i\}\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=2e5;
char s[N+10],t[N+10];
int pre[N+10],suf[N+10]; 
int main()
{
	int n,m;
	scanf("%d%d%s%s",&n,&m,s+1,t+1);
	for(int i=1,j=1;i<=n&&j<=m;i++)
	{
		if(s[i]==t[j])
		{
			pre[j]=i;
			j++;
		}
	}
//	for(int i=1;i<=m;i++) printf("%d ",pre[i]);/
	for(int i=n,j=m;i&&j;i--)
	{
		if(s[i]==t[j])
		{
			suf[j]=i;
			j--;
		}
	}
	int ans=0;
	for(int i=1;i<n;i++)
		ans=max(ans,suf[i+1]-pre[i]);
	printf("%d",ans);
	return 0;	
}

D

希望出题人没事。

\(x\) 的二进制表示成 \(x_1x_2\cdots x_{a+b}\)\(y\) 表示成 \(y_1y_2\cdots y_{a+b}\)。令 \(x_1=y_1=1\)\(x_{a+b-k}=y_{a+b}=1\),然后把所有剩余的 \(1\) 安排在满足 \(a_i=b_i=0\) 的位置上即可。如果有任意一个步骤无法满足,则输出 Noreturn 0

要特判 \(\bold{k=0}\)\(\bold{a=0}\) 的情况。

#include<bits/stdc++.h>
using namespace std;
const int N=2e5;
int x[N+10],y[N+10];
int main()
{
	int a,b,k;
	scanf("%d %d %d",&a,&b,&k);
	swap(a,b);
	int n=a+b;
	int ta=a,tb=b;
	if(k==0)
	{
		puts("Yes");
//		ta--;
		for(int i=1;i<=ta;i++) putchar('1');
		for(int i=1;i<=tb;i++) putchar('0');
		putchar('\n'); 
		for(int i=1;i<=ta;i++) putchar('1');
		for(int i=1;i<=tb;i++) putchar('0');
		return 0;
	}
	if(b==0)
	{
		if(k!=0)
		{
			puts("No");
			return 0;
		}
		else
		{
			puts("Yes");
			for(int i=1;i<=a;i++) putchar('1');
			putchar('\n');
			for(int i=1;i<=a;i++) putchar('1');
			putchar('\n');
		}
	}
	x[1]=y[1]=1;
	ta--;
	if(ta<0)
	{
		puts("No");
		return 0;
	}
	if(n-k<=1) 
	{
		puts("No");
		return 0;
	}
	x[n-k]=y[n]=1;
	ta--;
	if(ta<0)
	{
		puts("No");
		return 0;
	}
	for(int i=1;i<=n&&ta;i++)
	{
		if(!x[i]&&!y[i])
		{
			x[i]=y[i]=1;
			ta--;
		}
	}
//	if(ta>0)
//	{
//		puts("No");
//		return 0;
//	}
	printf("Yes\n");
	for(int i=1;i<=n;i++) printf("%d",x[i]);
	putchar('\n');
	for(int i=1;i<=n;i++) printf("%d",y[i]);
}

E

定义两行之间的差异值 \(\mathrm{diff}(x,y)=\sum\limits_{i=1}^m[s_{x,i}\not=s_{y,i}]\)。令 \(w=\max\limits_{i=2}^n\{\mathrm{diff(1,i)}\}\)\(id\) 表示取到 \(w\) 的行的编号,接下来就是 喜 闻 乐 见 的分类讨论:

  1. \(w\le 2\),直接输出第一行即可;
  2. \(w\ge 5\),无解;
  3. \(w=4\),则第一行与第 \(id\) 行一定都与答案的 \(\mathrm{diff}\) 都是 \(2\),枚举第 \(id\) 行哪两个数是正确的,将它们 copy 到第一行中,不断验证当前答案是否正确,如果不正确就还原初始状态,继续枚举;
  4. \(w=3\),则第一行与第 \(id\) 行分别有一个答案是正确的,有一个答案都无法确定是否是正确的。枚举都正确的那两个数,将第 \(id\) 行正确的数 copy 到第一行中,然后假设第一行无法确定的数是正确的,验证一遍,如果存在一行 \(x\) 使得 \(\mathrm{diff}\ge 3\) 就把第 \(x\) 行于第一行无法确定的数同列的数 copy 到第一行中并再验证一遍,如果还是不行就还原初始状态,继续枚举。

情况三最多验证 \(\mathrm{C}_4^2=6\) 遍,情况四最多验证 \(2\mathrm{C}_3^2=6\) 遍,是两个可以接受的常数。总的时间复杂度是 \(\mathcal O(nm)\)

#include<bits/stdc++.h>
using namespace std;
const int N=250000;
vector<int> a[N+10];
int n,m;
int dif(vector<int> x,vector<int> y)
{
	int ans=0;
	for(int i=1;i<=m;i++)
		ans+=(x[i]!=y[i]);
	return ans;
}
bool check()
{
	for(int i=2;i<=n;i++)
		if(dif(a[1],a[i])>2)
			return false;
	return true;
}
int check1()
{
	for(int i=2;i<=n;i++)
		if(dif(a[1],a[i])>2)
			return i;
	return 0;
}
int pos[N+10],cnt=0;
int main()
{
	// int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		a[i].push_back(0);
		for(int j=1;j<=m;j++)
		{
			int x;
			scanf("%d",&x);
			a[i].push_back(x);
		}
	}
	int mx=0,id=-1;
	for(int i=2;i<=n;i++)
	{
		int tmp=dif(a[1],a[i]);
		if(tmp>mx)
		{
			mx=tmp;
			id=i;
		}
	}
	if(mx<=2)
	{
		puts("Yes");
		for(int i=1;i<=m;i++) printf("%d ",a[1][i]);
	}
	else if(mx>=5)
		puts("No");
	else if(mx==4)
	{
		for(int i=1;i<=m;i++)
			if(a[1][i]!=a[id][i])
				pos[++cnt]=i;
		for(int i=1;i<=cnt;i++)
		{
			for(int j=i+1;j<=cnt;j++)
			{
				int pi=pos[i],pj=pos[j];
				int ti=a[1][pi],tj=a[1][pj];
				a[1][pi]=a[id][pi];
				a[1][pj]=a[id][pj];
				if(check())
				{
					puts("Yes");
					for(int i=1;i<=m;i++) printf("%d ",a[1][i]);
					return 0;
				}
				a[1][pi]=ti;
				a[1][pj]=tj;
			}
		}
		puts("No");
	}
	else if(mx==3)
	{
		for(int i=1;i<=m;i++)
			if(a[1][i]!=a[id][i])
				pos[++cnt]=i;
		// printf("pos:\n");
		// for(int i=1;i<=cnt;i++) printf("%d ",pos[i]);
		for(int i=1;i<=cnt;i++)
		{
			for(int j=1;j<=cnt;j++)
			{
				if(i==j) continue;
				int pi=pos[i],pj=pos[j],pk=pos[6-i-j];
				int ti=a[1][pi],tj=a[1][pj],tk=a[1][pk];
				// a[1][pi]=a[id][pi];
				a[1][pj]=a[id][pj];
				int tmp=check1();

				if(!tmp)
				{
					puts("Yes");
					for(int i=1;i<=m;i++) printf("%d ",a[1][i]);
					return 0;
				}
				a[1][pk]=a[tmp][pk];
				tmp=check1();
				if(!tmp)
				{
					puts("Yes");
					for(int i=1;i<=m;i++) printf("%d ",a[1][i]);
					return 0;
				}
				a[1][pi]=ti;
				a[1][pj]=tj;
				a[1][pk]=tk;
			}
		}
		puts("No");
	}
	return 0;
}
posted @ 2021-02-23 23:58  zzt1208  阅读(98)  评论(1编辑  收藏  举报