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去做下面操作的一种
- 变换一个袜子的颜色
- 将一个袜子的左右属性变化
试求出花费的最小代价使得所有袜子都可以匹配
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;
}