codeforce round 554 div2 解题报告 (A -> D)

A. Neko Finds Grapes
题目大意:两个序列a,b。选出ai,bj进行匹配,要求ai + bj 是奇数,每个数字只能匹配一次,被匹配一次,求最大的匹配对数,
解法:扫描两个序列即可,答案是唯一的,记下扫描a序列的奇数的个数和偶数个数,扫描b的时候直接得出答案。

B. Neko Performs Cat Furrier Transform
题目大意:给一个数字 x,有两种操作,A操作是异或上一个 2^m - 1的数字,B操作是替换成x + 1,要求通过不超过40次操作,每次轮流使用两个操作,将x变成一个 2 ^ k - 1这样的数字。
解法:从二进制角度,就是消去非前导0,使得每一位全是1,x + 1操作对我们来说没什么用,因为是轮流使用,不是随时使用。因为最前面一串连续的1可搞可不搞,所以可以从最前面一个0开始消去,找到最前面的0的位置k,然后异或上 (1 << (k + 1) ) - 1 ,发现最前面的0的数量总是在往后移,最后总能全部清掉,得到一个每一位都是1的数字。题目说数字 x < 10^6,也就是少于20位,我们最多只需要移动不到20次,交替执行的情况下最差也低于40次,完全可解,因此模拟搞一下即可。

#include<bits/stdc++.h>
using namespace std;
vector<int> g;
int find(int x) {
	int cnt = 0;
	int ans = -1;
	while(x) {
		if((x & 1) == 0) ans = cnt;
		cnt ++;
		x >>= 1;
	}
	return ans;
}
int main() {
	int x;
	scanf("%d",&x);
	int cnt = 0;
	int p;
	while((p = find(x)) != -1) {
		if(cnt % 2) 
			x++;
		else{
			p = find(x);
			p++;
			x ^= (1 << p) -1;
			g.push_back(p);
		}
		cnt++;
	}
	if(cnt)
		printf("%d\n",cnt);
	else printf("0\n");
	for(int i = 0; i < g.size(); i++)
		printf("%d ",g[i]);
	return 0;
}

C. Neko does Maths
题目大意:有两个正数a,b,求一个k使得,lcm(a + k,b + k)最小。
解法:lcm(x,y) 的求法我是通过 x * y / gcd(x,y) 来求的。
gcd(a + k,b + k) = gcd(a + k,b - a)。(辗转相除法,减掉一倍模 a + k 余数不变,gcd也就不会变)
b - a是固定值,可以得到一个结论:gcd(a + k,b - a) 尽量大,可以使得lcm(a + k, b + k)尽量小。
当a < b - a时,我们可以设置k的值使得 gcd(a + k,b - a) = a + k。当 a > b - a时,可以设置k的值使得gcd(a + k,b - a) = b - a。从贪心的角度,如果是前面一种情况,a + k应该是 b - a 的一个因子,且是a最靠近的一个因子,后一种情况 a + k 是 b - a的倍数,且是a 最接近的 b - a的倍数。先得到 b - a的所有因子,不会超过128个。然后判断是哪种情况,从而使用哪种决策。特判一下 b = a的情况,直接输出0,不然后面会有除0错误。

#include<bits/stdc++.h>
using namespace std;
long long a,b,tmp;
long long gcd(long long a,long long b) {
	return !b ? a : gcd(b,a % b);
}
vector<long long> g;
int main() {
	scanf("%lld%lld",&a,&b);
	if(a > b) swap(a,b);
	long long t = b - a;
	if(t == 0) {
		puts("0");
		return 0;
	}
	for(long long i = 1; i * i <= t; i++) {
		if(t % i == 0) {
			g.push_back(i);
			if(t / i != i) 
				g.push_back(t / i);
		}
	}
	sort(g.begin(),g.end());
	if(a < t) {
		int p = lower_bound(g.begin(),g.end(),a) - g.begin();	//找到最接近的因子
		printf("%lld\n",g[p] - a);
	}
	else {
		tmp = a / t;
		if(a % t) tmp++;		//最接近的倍数
		printf("%lld\n",t * tmp - a);
	}
	return 0;
}

D. Neko and Aki’s Prank
解法:dp + 思维 + 贪心
链接:https://blog.csdn.net/qq_41997978/article/details/89575281

猜你喜欢

转载自blog.csdn.net/qq_41997978/article/details/89575875