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

这次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队里好多人都涨分了。。自己还是队里分数最低的几个之一,希望自己能够快快涨分吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值