欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Codeforces Round #609 (Div. 2) A,B,C题详细题解

程序员文章站 2022-04-01 18:33:41
...

这次CF感觉是一个上分特别好的机会,可惜我英语太屎了,看不懂AB两题。。最后只AC了C题居然也能上分,一 题 涨 分 传 说。

A题:Equation

1.大概题意:
输入一个n,输出两个合数a,b使得a-b=n;
2.思路:
签到题,题目保证ab一定是存在的,而且只需要输出其中的一个特解即可。可以知道如果n是偶数或者0(即mod2后余数为0),那么它加上4之后一定是一个合数,同理如果n是奇数,那么它加上9之后一定会得到一个合数。
3.代码:

#include<iostream>
using namespace std;
int main(){
	int n;
	while(scanf("%d",&n)!=EOF){
		if(n%2==0){
			cout<<4+n<<' '<<4<<endl;//偶数+4必为合数
		}
		else{
			cout<<9+n<<' '<<9<<endl;//奇数+9必为合数
		}
	}
	return 0;
}

B题:Modulo Equality

1.大概题意:
先给两个数,1≤n≤2000,1≤m≤1e9,n是集合的元素数量,m是模数
给两个集合a,b,我们要找到一个最小的x解使得(a[i]+x)mod m==b[j],即a的每个元素加x再模m以后可以与b中的元素一一对应。
2.思路:
暴力枚举a[0]和b的每个元素的差模m。其实就是枚举a[0]是对应b中的哪一个,复杂度O(N)。
把a中的每个元素+x模m之后的数储存在c中并且对c排序,这样方便之后的比较。
还有就是用到了取模运算的分配率(a + b) % p = (a % p + b % p) % p
还有结合律((a+b) % p + c) % p = (a + (b+c) % p) % p
在这题中的体现就是(a[i]+x)%m=b[j]
通过移项变成x=(a[i]-b[j]+m)%m
3.看代码:

#include<iostream>
#include<algorithm>
using namespace std;
#define INF 0x7f7f7f7f
int a[2010],b[2010],c[2010]; 
int main(){
	int flag,x,n,m,minx;
	while(scanf("%d%d",&n,&m)!=EOF){
		minx=INF;//因为是要找到最小的解,所以用minx保存 
		for(int i=0;i<n;i++) scanf("%d",&a[i]);
		for(int i=0;i<n;i++) scanf("%d",&b[i]);
		sort(b,b+n);//对b排序 
		for(int i=0;i<n;i++){
			flag=1;
			x=(b[i]-a[0]+m)%m;
			for(int j=0;j<n;j++){
				c[j]=(a[j]+x)%m;//通过加x模m得到新的集合c 
			}
			sort(c,c+n);//对c进行排序,方便之后的比较 
			flag=1;
			for(int i=0;i<n;i++){
				if(c[i]!=b[i]){ //这边再检查c和b两个集合是不是相同的 
					flag=0;break;
				}
			}
			if(flag) minx=min(x,minx);//如果确定了bc两个集合是一样的,则记录最小的x 
		}
		cout<<minx<<endl;
	}
	return 0;
}

这题我其实参考的是队里洪某大佬的思路,如果要一对一枚举的话那么复杂度就要是O(N^2)了,枚举a[0]对应的元素其实就是枚举x。

C题:Long Beautiful Integer

1.大概题意:
给了数字长度n和循环的长度k*(2≤n≤200000,1≤k<n)*
把数字的每一位分成a[1],a[2],a[3]…a[n];
如果这个数字的每个位数之间满足a[i+k]=b[i],则称这串数字为美丽的数字。
2.思路:
我的思路是从最高k位找到循环,然后往后看是不是都是这样循环下去。
如果有a[i+k]!=b[i]的情况,这边分成两种:
一种是b[i]>a[i+k]的情况
那么就是可以直接加上去的,执行过这个之后我用flag记录是否进行过这种增加操作。如果进行过了这种增加操作,之后的b[i]<a[i+k]的情况就不用改变前面的循环了,也就是说之后的数字就可以*改变了,就把循环一次一次往下套。如果进入了这种无脑套的情况,用flag=1来记录。
另外一种是b[i]<a[i+k]的情况
考虑如果flag没有记录,则在循环的最后一位上加上1,如果进行过了这个操作,同理把flag变成1,之后的数字就可以随便改了。
这题还需要考虑如果循环在+1以后需要进位的情况。
3.看代码:

#include<iostream>
#include<cstring>
using namespace std;
char a[200010];
int main(){
	int n,st,ch,k,flag;
	while(scanf("%d%d",&n,&k)!=EOF){
		flag=0;//flag用来记录 
		getchar();
		for(int j=1;j<=n;j++){
			scanf("%c",&a[j]);
		}
		st=1;ch=k+1;//st就是在循环的k位数字之间轮流来,ch是检查后面的数字是否依照循环?
		while(a[ch]<=a[st]&&ch<=n){//如果是小于的情况,不需要改变的最后一位 
			if(a[ch]<a[st]&&flag==0){//进行过这种增加的操作之后用flag记录。
				flag=1;
			}
			a[ch]=a[st];//把不符合的位数变成与循环对应的情况
			st=st%k+1;ch++;
		}
		if(ch!=n+1){//如果出现了大于的情况,就是在中途退出了循环 
			if(flag==0){//如果没有进行过前面的增加操作,则循环的最后一位需要+1 
				a[k]++; 
				for(int i=k;i>=1;i--){
					if(a[i]>'9'){//考虑进位的情况 
						a[i]='0';a[i-1]++;
					}
					else break;
				}
			}
			st=1;ch=k+1;
			while(ch<=n+1){
				a[ch]=a[st];//无脑往下循环 
				st=st%k+1;ch++;
			}
		}
		cout<<n<<endl; 
		for(int i=1;i<=n;i++){
			cout<<a[i];
		}
		cout<<endl;
	}
}

总结

这次cf队里好多人都涨分了。。自己还是队里分数最低的几个之一,希望自己能够快快涨分吧!

相关标签: acm竞赛