Codeforces Round # 704 Editorial 题解(A-D)

Codeforces Round # 704 Editorial 题解(A-D)

A. Three swimmers

题目大意:

\(p,a,b,c\)四个数,问p最少要加上多少才能到达\(a,b,c\)某个数的倍数(包括0)。

解题思路:

很明显离p最近a的倍数是\(\left\lceil\frac{a}{p}\right\rceil\times a\),同理可得离b和c最近的是\(\left\lceil\frac{b}{p}\right\rceil\times b\)\(\left\lceil\frac{c}{p}\right\rceil\times c\)

所以答案就是\(min(\left\lceil\frac{a}{p}\right\rceil\times a,\left\lceil\frac{b}{p}\right\rceil\times b,\left\lceil\frac{c}{p}\right\rceil\times c)-p\)

代码如下:
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
int q;
LL p,a,b,c;
int main()
{
	cin>>q;
	while(q--){
		cin>>p>>a>>b>>c;
		LL res=(p+a-1)/a*a;
		res=min(res,(p+b-1)/b*b);
		res=min(res,(p+c-1)/c*c);
		cout<<res-p<<endl;
	}
	return 0;
}

B. Card Deck

题目大意:

\(n\)张互不相同的卡片,每张卡片的数值\(p_i\in[1,n]\),所有的卡片按照顺序堆叠在一起,\(p_i\)在堆底,\(p_n\)在堆顶。每一步可以选择从牌堆顶部拿\(k\)张牌(\(k>0\)) ,现在要使得将原牌堆取空之后新牌堆的顺序最小,牌堆顺序的计算公式是\(\sum\limits_{i=1}^n n^{n-i}\)

解题思路:

很显然最优方案就是字典序最大的那个方案,因为一旦存在字典序更大的方案,当前的方案一定不是最优,仍然还有提升的空间。为了使得方案是最大的字典序,我们只要在每次操作的时候将牌堆中的最大值取出来放在最前面就可以了。时间复杂度\(O(n)\)

代码如下:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
int p[maxn],Max[maxn],Index[maxn];
int q,n;
int main()
{
	scanf("%d",&q);
	while(q--){
		scanf("%d",&n);
		for(int i=1;i<=n;i++) scanf("%d",&p[i]);
		for(int i=1;i<=n;i++){//Max[i]存储[1,i]中的最大值,Index[i]存储最大值对应的下标 
			if(p[i]>Max[i-1]){
				Max[i]=p[i];
				Index[i]=i;
			}
			else{
				Max[i]=Max[i-1];
				Index[i]=Index[i-1];
			}
		}
		for(int i=n;i>=1;i--){
			int x=Index[i];
			for(int j=x;j<=i;j++){//每次从最大值的位置抽到牌顶 
				printf("%d ",p[j]);
			}
			i=x;
		}
		puts("");
	}
	return 0;
}

C. Maximum width

题目大意:

给定两个字符串\(s\)\(p\),存在一个序列\(p_1,p_2,\cdots,p_m\)使得每一个\(p_i\)都有\(s_{p_i}=t_i\),求\(\max\limits_{1<=i<m}(p_{i+1}-p_i)\)

解题思路:

通过找到每一个\(pi\)最能达到的最小值和最大值,记\(pi\)的最小值是\(l_i\),最大值是\(r_i\),那么答案就是\(\max\limits_{1<=i<m}r_{i+1}-l_i\)

只需要正向和方向各遍历一遍就能得到所有的\(l_i\)\(r_i\)。时间复杂度\(O(n+m)\).

代码如下:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=2e5+10;
int n,m;
char a[maxn],b[maxn];
int l[maxn],r[maxn];
int main()
{
	scanf("%d%d",&n,&m);
	scanf("%s%s",a+1,b+1);
	for(int i=1,j=1;j<=m;j++){
		while(a[i]!=b[j]) i++;
		l[j]=i;
		i++;
	}
	for(int i=n,j=m;j>=1;j--){
		while(a[i]!=b[j]) i--;
		r[j]=i;
		i--;
	}
	int res=0;
	for(int i=1;i<m;i++)	res=max(res,r[i+1]-l[i]);	
	cout<<res<<endl;
	return 0;
}

D. Genius's Gambit

题目大意:

给定三个整数\(a,b,p\),找到两个二进制数\(x,y(x>=y)\),且\(x\)\(y\)都由\(a\)个0和\(b\)个1组成,并且\(x-y\)(写作二进制)恰好有\(k\)个1.

\(x\)\(y\)不能含有前导零。

问是否能找到这样两个数,如果能找到就输出“Yes"和这两个数,否则输出”No"。

解题思路:

首先可以明确的是,因为不能存在前导零,我们必须在最高位上放一个1。那么对于\(b=1\)\(a=1\)我们都只能找到两个一样的数,所以当k不为0的时候,直接输出"No”,当k为0的时候我们直接将\(b\)个1和\(a\)个0输出就行。

除此之外,我们可以通过观察样例可以发现1000和0001相减可以得到4个1。

扩展一下可以得到\(\begin{matrix}n个\\\overbrace{1xx\dots0}\end{matrix}\)\(\begin{matrix}n个\\\overbrace{0xx\dots1}\end{matrix}\)相减可以得到n-1个个1,只要其中对应位上的x相等就行,算上首位不可或缺的1,a+b个数最多可以使得\(x-y\)\(a+b-2\)个1,所以当k>a+b-2时,直接输出“No"就行了。

得到了上述的信息,那么我们就可以针对这种情况构建出来对应的\(x\)\(y\)

第一步: 因为不能存在前导零,在\(x\)\(y\)的首位放上一个1

第二步: 因为只需要\(k+1\)个数即可构造出k个1,会存在\(a+b-1-(k-1)=a+b-k-2\)个数是多余的,所以我们将多余的0和1排在首位的后面,使得在相减的过程中全部消成0

第三步:构造出\(\begin{matrix}k+1个\\\overbrace{1xx\dots0}\end{matrix}\)\(\begin{matrix}k+1个\\\overbrace{1xx\dots0}\end{matrix}\)两种结构。

代码如下:
#include<cstdio>
#include<iostream>
using namespace std;
int a,b,k;
int main()
{
	cin>>a>>b>>k;
	if(b==1||a==0||k==0){//特判情况 
		if(k==0){
			puts("Yes");
			for(int i=0;i<b;i++)  putchar('1');
			for(int i=0;i<a;i++)  putchar('0');
			puts("");
			for(int i=0;i<b;i++)  putchar('1');
			for(int i=0;i<a;i++)  putchar('0');
			puts("");
		}
		else puts("No");
	}
	else if(k>a+b-2){
		puts("No");
	}
	else{
		int cnt=a+b-k-2,n0=a,n1=b;//cnt表示多余的数 
		//输出x 
		puts("Yes");
		putchar('1');n1--;//首位的1
		while(n1>1&&cnt) putchar('1'),n1--,cnt--;//留一个1给后面构造用 
		while(n0>1&&cnt) putchar('0'),n0--,cnt--;//留一个0给后面构造用 
		while(n1) putchar('1'),n1--;
		while(n0) putchar('0'),n0--;
		puts("");
		
		cnt=a+b-k-2,n0=a,n1=b;
		//输出y 
		putchar('1');n1--;//首位的1 
		while(n1>1&&cnt) putchar('1'),n1--,cnt--;//留一个1给后面构造用 
		while(n0>1&&cnt) putchar('0'),n0--,cnt--;//留一个0给后面构造用 
		putchar('0');n0--;
		while(n1>1) putchar('1'),n1--;
		while(n0) putchar('0'),n0--;
		putchar('1');
		puts("");
	}
	return 0;
}

posted @ 2021-02-27 05:47  陌默丶  阅读(53)  评论(0)    收藏  举报