Codeforces 刷题3

这篇博客详细介绍了Codeforces上的四道编程题目,涉及数组异或操作达到所有元素相同、袜子匹配的最小代价、构造代价最小的字符串以及栅栏涂色问题。通过异或前缀和、袜子颜色和数量优化、字符串构造模式和动态分配油漆工等策略进行解题分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.AGAGA XOOORRR

题目大意
给定一个长度为 n 的数组 a ,每次可以选择相邻的两个数进行异或运算,并用结果替换这两个数,试问能否有一种策略,使操作后的数组的每一个元素都相同(数组元素个数大于等于2)
解题思路
考虑最后的结果,尽可能把剩余的数最小化,那么可以发现最少只可能为2或3个数相同如果大于3,可以继续进行异或化为最少情况,又因为每次都取连续的两个数,所以直接对两种情况分别讨论,枚举分界点,用异或前缀和优化即可。
(异或运算也可以用前缀和优化)

#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdio>
#include<set>
#include<stack>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int mod = 1e9 + 7;
const int N = 2e5 + 100;
ll a[2010];
ll pre[2020];
vector<int> G[2010];
int main(){
	int t;
	cin>>t;
	while(t--){
		memset(pre, 0, sizeof pre);
		int n;
		cin >> n;
		for (int i = 1; i <= n;i++){
			cin >> a[i];
			pre[i] = pre[i - 1] ^ a[i];
		}
		if(n==2){
			if(a[1]==a[2]){
				cout << "YES" << endl;
			}
			else{
				cout << "NO" << endl;
			}
		}
		else{
			bool cann = 0;
			for (int i = 1; i <= n - 1;i++){
				if(pre[i]==(pre[n]^pre[i])){
					cann=1;
					break;
				}
			}
			if(cann){
				cout << "YES" << endl;
				continue;
			}
			else{
				for (int i = 1; i <= n - 2;i++){
					for (int j = i + 1; j <= n - 1;j++){
						if(pre[i]==(pre[j]^pre[i])&&pre[i]==(pre[n]^pre[j])){
							cann = 1;
							break;
						}
					}
				}
				if(cann){
					cout << "YES" << endl;
				}
				else{
					cout << "NO" << endl;
				}
			}
		}
	}
	return 0;
}

(要仔细读题,没看到连续的限定条件,直接卡住了。。。)

B.Phoenix and Socks

题目大意
给定一个长度为n的代表袜子数组a,前 l 个代表左脚袜子,后面的代表右脚袜子,每一个ai的值代表这个袜子的颜色,你可以花费代价1去做下面操作的一种

  1. 变换一个袜子的颜色
  2. 将一个袜子的左右属性变化

试求出花费的最小代价使得所有袜子都可以匹配
n保证为偶数
解题思路
首先将已经匹配的拿出来,这一部分不用做任何处理,剩余的袜子要匹配首先得保证左右脚数目一样,所以在调配左右脚袜子时,假设左脚的较多,那么优先将数目大于1的进行变换,这样就可以省去颜色变换的步骤。

#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdio>
#include<set>
#include<stack>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int mod = 1e9 + 7;
const int N = 2e5 + 100;
int c[N];
int numl[N], numr[N];
vector<int> G[N];
bool cmp(int a, int b){
	return a > b;
}
int main(){
    std::ios::sync_with_stdio(false);
	int t;
	cin>>t;
	while(t--){
		memset(numl, 0, sizeof numl);
		memset(numr, 0, sizeof numr);
		int n, l, r;
		cin >> n >> l >> r;
		for (int i = 1; i <= n;i++){
			cin >> c[i];
			if(i<=l)
				numl[c[i]]++;
				else
					numr[c[i]]++;
		}
		for (int i = 1; i <= n;i++){
			int minn = min(numl[i], numr[i]);
			numl[i] -= minn;
			numr[i] -= minn;
			l -= minn;
			r -= minn;
		}
		if(l < r){
			swap(l ,r);
			swap(numl, numr);//可以直接交换数组
		}//做一下调整,直接默认左脚多
		int ans = 0;
		int tt = 0;
		for (int i = 1; i <= n;i++){
			int ext = l - r;
			int doo = min(numl[i] / 2, (l - r) / 2);
			ans += doo;//记录交换的次数
			tt += doo;
			l -= doo;
			r += doo;
		}
		ans += (l - r) / 2 + (l + r) / 2 - tt;//由于同色交换不需要加上变色那一步,所以把多余的步数减掉。
		cout << ans << endl;
	}
	return 0;
}
3.Min Cost Strinb

题目大意
对于一个字符串,当出现si = sj 且si+1 = sj+1(i < j)时这个字符串的代价加1,尝试构造一个长度为 n ,只包含前 k 个小写字母的字符串使代价最小。
解题思路
本题属于构造题,一般先仔细观察题目和样例给的隐藏提示
以样例1为基础这样思考
aa ab ac ad bb bc bd …
但是会有连续三个相同字母,故可以优化为
aa ba ca da bb cb db cc…
又因为在每个字母结束轮到下一个字母开始时,又会产生相同的字母对,所以进一步优化,把每个字母结束时的最后一个删除
aa ba ca d bb cb d cc d d aa…
发现正好是样例1
所以就按这种方式不断循环直到字符串长度到n为止

#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdio>
#include<set>
#include<stack>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int mod = 1e9 + 7;
const int N = 2e5 + 100;
char a[30];
bool cmp(int a, int b){
	return a > b;
}
vector<int> G[30];
vector<char> ans;
int n, k;
void solve(){
	int cnt = 0;
		while(1){
			for (int i = 0; i < k;i++)
				for (int j = i; j < k;j++){
					char tot = 'a' + j;
					ans.push_back(tot);
					cnt++;
					if(cnt==n)
						return;
						if(j == k - 1){
							continue;
						}
						char tot2 = 'a' + i;
						ans.push_back(tot2);
						cnt++;
						if(cnt==n){
							return;
						}
				}
		}
		for (int i = 0; i < n;i++){
			cout << ans[i];
		}
 
}
int main(){
    std::ios::sync_with_stdio(false);
	a[1] = 'a';
	for (int i = 2; i <= 26;i++){
		a[i] = a[i - 1] + 1;
	}
	cin >> n >> k;
	if(n <= k){
		for (int i = 1; i <= n;i++){
			cout << a[i];
		}
	}
	else{
		solve();
		for (int i = 0; i < n;i++){
			cout << ans[i];
		}
	}
	return 0;
}
4. Fence Painting

题目大意
你有一个长度为 n 的栅栏,每个栅栏有一个初始颜色 ai ,现在你要把栅栏的每一块涂成 bi,你有m个依次到来的油漆工,每个人会把一块栅栏涂成 ci,而且每个人必须涂一块,输出能否满足将每个栅栏都变为所需颜色的条件,如果可以,接着输出每个油漆工涂了那一块栅栏
解题思路
首先已经匹配的栅栏不需要再染色,把它们排除掉,记录剩下的还未匹配的栅栏,对于每一个ci,如果这个颜色在数组b里有,那么如果有需要涂色的就涂上,没有就找一块已经匹配的涂上,如果碰到b中没有的颜色先保存下来,之后遇到数组b中有的颜色时,把他们全都分配到当前ci要涂的点上去,最后看看是否都匹配,并且没有再保存数组b之外的颜色即为成功。

#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdio>
#include<set>
#include<stack>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int mod = 1e9 + 7;
const int N = 1e5 + 100;
int a[N];
int b[N];
int c[N];
int tag[N];
int ans[N];
vector<int> G[N];
int main(){
    std::ios::sync_with_stdio(false);
	int t;
	cin>>t;
	while(t--){
		queue<int> wro;
		int n, m;
		cin >> n >> m;
		for (int i = 1; i <= n;i++){
			cin >> a[i];
			G[i].clear();
		}
		map<int, bool> hass;
		for (int i = 1; i <= n;i++){
			cin >> b[i];
			hass[b[i]] = true;
			if(b[i]!=a[i]){
				G[b[i]].push_back(i);
			}
			else{
				tag[b[i]] = i;
			}
		}
		for (int i = 1; i <= m;i++){
			cin >> c[i];
			if(hass[c[i]]){
				if(G[c[i]].size()){
					if(wro.size()){
						while(wro.size()){
						    ans[wro.front()] = G[c[i]][G[c[i]].size() - 1];
						    wro.pop();
						}
					}
					ans[i] = G[c[i]][G[c[i]].size() - 1];
					tag[c[i]] = G[c[i]][G[c[i]].size() - 1];
					G[c[i]].pop_back();
				}
				else{
					if(wro.size()){
						while(wro.size()){
							ans[wro.front()] = tag[c[i]];
							wro.pop();
						}
					}
					ans[i] = tag[c[i]];
				}
			}
			else{
				wro.push(i);
			}
		}
		bool cann = 1;
		for (int i = 1; i <= n;i++){
			if(G[i].size()){
				cann = 0;
			}
		}
		if(wro.size()){
			cann = 0;
		}
		if(!cann){
			cout << "NO" << endl;
		}
		else{
			cout << "YES" << endl;
			for (int i = 1; i <= m;i++){
				cout << ans[i] << ' ';
			}
			cout << endl;
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值