CF-Round#630 A-D

题目传送门

A. Exercising Walk

刚开始一看,cf,div2的A题居然这么长,是很难么,结果仔细才发现这就是一道水题,div2A题的通性就是判断。题目的大概意思就是主人公养了一只猫,这天想让这只猫在一个矩阵里面走动,且不能超出矩阵,是否能完成训练。那么我们可以把上下走动抵消掉只看成向下或者向上走,向左向右同理,而这里只需要一个特判,即矩阵的行或者列只有1格,但猫不需要向上或下走
主要代码如下:

int T;cin>>T;
	while(T--){
		bool flag1 = false,flag2 = false;//分别判断猫是否能左右走和上下走
		int a,b,c,d;cin>>a>>b>>c>>d;
		int x,y,x1,y1,x2,y2;cin>>x>>y>>x1>>y1>>x2>>y2;
		int cc = b-a,rr = d-c;//猫向左or右,走上or下。
		//特判是否本身就不需要左右走
		if(a+b){
			//判断矩阵列是否只有一格
			if(x2-x1!=0&&x1<=cc+x&&x2>=cc+x)flag1 =true;
		}else flag1 = true;
		//特判是否本身就不需要上下走
		if(c+d){
			if(y2-y1!=0&&y1<=rr+y&&y2>=rr+y)flag2 = true;
		}else flag2 = true;
		if(flag1&&flag2)cout<<"YES\n";
		else cout<<"NO\n";
	}

B.Composite Coloring

这题的大致意思就是,给你一些合数,要你把他们涂上颜色,总共可以用的颜色种类不能超过11种,且所用的颜色的编号必须连续,不能中断,且gcd(a,b)!=1的可以涂上相同或者说不同颜色。那由唯一分解定理我们可以知道,任何一个合数都可以分解成若干个素数相乘,颜色种类不能超过11种即素数的数目不超过11个,那么就可以暴力从小到大枚举每个合数的质因子,并给枚举到的质因子附上编号,按出现的先后顺序赋值,这样就不会中断。
主要代码如下:

int b[1005];
int T;cin>>T;
	const int primes[]{2,3,5,7,11,13,17,19,23,29,31};//11个由小到大的质因子
	int col[32];//质因子最大为31,初始全部赋值为零
	while(T--){
		int cnt =0;
		int n;cin>>n;
		int ans = 0;//统计用了几种颜色
		for(int i = 0;i<32;++i)col[i]=0;
		for(int i =0;i<n;++i){
			cin>>b[i];
			for(int j = 0;j<11;++j){
			//判断是否能被这个质因子整除,若能,染色退出
				if(b[i]%primes[j]==0){
				//判断质因子是否在之前出现过
					if(!col[primes[j]]){
						++ans;
						col[primes[j]] = ++cnt;
						b[i] = col[primes[j]];
					}else b[i] = col[primes[j]];
					break;
				}
			}
		}
		cout<<ans<<'\n';
		for(int i =0;i<n;++i)cout<<b[i]<<" \n"[i==n-1];
	}

C.K-Complete Word

题意大概就是,给你一个长度为n字符串,要你更改其中的一些字符,使其能变成一个回文串,且是一个周期为k的周期串,求更改字符的最小数目。
预处理+贪心
首先我们要让这个串变成一个周期为k的回文串的话,那么将这个串分为n/k段,每一段都要是回文串,我们只需要统计一下每一段对应的每一位中,每种字符的贡献,再将这一整串看成一段长度为k的字符串,因为这是一个回文串,所以从两端开始遍历,贪心去求,求出贡献最大的字符,用n/k*2-贡献即为这一位对应的所有段需要更改的字符数,要注意段长为奇数偶数的情况。(每次不要用memset去清零统计数组,笔者深受memset毒害
主要代码如下:

const int INF = INT_MAX;
const int N = 2e5+5;
int cnt[N][26]
int T; cin >> T;
	while (T--) {
		int k, n; cin >> n >> k;
		string s; cin >> s;
		int cut = n / k;//一共有多少段
		//手动清零统计数组
		for(int i =0;i<n;++i){
			for(int j = 0;j<26;++j)
					cnt[i][j]=0;
		}
		//统计每一段对应的位上,每种字符的贡献
		for(int i = 0;i<n;++i) {
			cnt[i % k][s[i] - 'a']++;//i%k的原因是因为,将一串化为一段
		}
		ll ans = 0;
		//两端开始遍历
		for (int i = 0, j = k - 1; i <= j; i++, j--) {
			int ma = -INF;
			//遍历26个字符,取贡献最大的
			for(int k = 0;k<26;++k){
				int cost = cnt[i][k]+(i==j?0:cnt[j][k]);//段长为奇数时,会同时遍历到中间
				ma = max(ma,cost);
			}
			if(i==j)ans += cut - ma;
			else ans += cut*2 - ma;
		}
		cout << ans << '\n';
	}

D.Walk on Matrix

粗略的一看,哇,这题dp,不想写了。
这题的题意,确实和dp有关,但是实现的时候,不关dp的事
他给了你一个矩阵nxm,矩阵的每个格子都有权值,玩家的初始分数是 a 1 , 1 a_{1,1} ,然后从 a 1 , 1 a_{1,1} 开始,每一步只能向下或者向左走,走到 a n , m a_{n,m} ,每走一格,玩家的分数为(自身的&该位置的权值),求玩家可获得最大的分数,题目给出了dp的算法,但这个算法是错的,要求你构造一个矩阵,使正确答案的值与错误答案的值相差为k.
如果说用dp来写这道题,必然会出现忽略了更大的值这种情况,因为按位取与和直接相加是不一样的,你可能取与的时候,忽略了更大位数的值。解题大致思想就是诱导致使其只能获得你的值
因为k<1e5 则我们可以取一个k达不到的数base = 1<<17(二进制数位中,base只有一个1)
如下矩阵

 base+k base   k
 k      base+k k

主代码如下:

int k;cin>>k;
int inf = 1<<17;
cout<<2<<' '<<3<<'\n';
cout<<inf+k<<' '<<inf<<' '<<k<<'\n';
cout<<k<<' '<<inf+k<<' '<<k<<'\n';

新人第一次写题解,可能会有些地方有问题,请大家指出=3=

发布了1 篇原创文章 · 获赞 3 · 访问量 72

猜你喜欢

转载自blog.csdn.net/qq_20520073/article/details/105274668