题解:P15036 「chaynOI R2 T1」构造字符串
deepthinks · · 题解
这场比赛太难了,我也太菜了,只做出来这一道题。
简化题目
初始有一个空字符串
操作:
-
操作一:在
s 最后面加入一个字符串(只限a、b、c),要求是s 中还没有这个字符。 -
操作二:在
s 中,对于任意一对相邻且不同的字符,如果是a、b,就把第二个字符换成c,如果是c、b,就把第二个字符换成a,以此类推。
打个比方,ba,我们可以在后面加上 c,也可以把后面的 a 换成 c。
思路
第一个难点是长度,怎么把他变成
很明显,只能用操作一,但是不能重复,所以我们可以一旦字符种类出现第三种,我们就用操作二把他给替换掉,然后再加一个第三种字符。我们把第三种字符种类称为其他字符。
注意到操作二只不能对第一个字符操作,所以在操作一的时候就应该加
所以流程就是先加入一个头字符,再加入另外两种字符中其中任意一种字符(让我们把它称为中字符),再加入其他字符,把其他字符串换成首字符后再加入其他字符,把其他字符串换成中字符后再加入其他字符······
然后就得到了一个长度为
接下来看看
如果两类都不符,那就特殊一点,对前面那一个字符进行操作二,再对当前这一个字符进行操作二,然后又对前面那一个字符进行操作二(两次操作二相当于没变,和异或很像)。
记得从后往前判断,不然前面的答案会影响后面的。
然后交了一发,结果错了?
原来因为超过了限制,所以错了几个点。
卡常
见过对时间、空间卡常的,没见过对答案卡常的。
优化方法1
所以流程就是先加入一个首字符,再加入另外两种字符中其中任意一种字符(让我们把它称为中字符)
注意到是任意,那么答案肯定不会是百分之百最优的,所以我们可以看看两种情况的答案,然后选最优的就可以了。
优化方法2
如果两类都不符,那就特殊一点,对前面那一个字符进行操作二,再对当前这一个字符进行操作二,然后又对前面那一个字符进行操作二(两次操作二相当于没变,和异或很像)。
两次操作二相当于没变,那是不是如果前面那一个字符后面本来就是要进行操作二的,那就不重复操作了。
这些优化方法本来就很玄学,如果被卡了叫我,我再优化优化。
代码
#include <bits/stdc++.h>
using namespace std;
struct node{
int t,id;
char ch;
};
vector<node> v1,v2,v;
string str,s1,s2;
int n;
char a,b,c;
int main(){
ios::sync_with_stdio(0);
cout.tie(0);cin.tie(0);
cin>>str;
a=str[0];n=str.size();
str=" "+str;
if(a=='a') b='b',c='c';
else if(a=='b') b='c',c='a';
else if(a=='c') b='a',c='b';
//
v1.push_back(node{1,-1,a});
s1+=a;
v1.push_back(node{1,-1,b});
s1+=b;
for(int i=3;i<=n;i++){
v1.push_back(node{1,0,c});
v1.push_back(node{2,i,' '});
if(i%2==1) s1+=a;
else s1+=b;
}
s1=" "+s1;
for(int i=n;i>=2;i--){
if(s1[i]==str[i]) continue;
else if(str[i]==c) v1.push_back(node{2,i,' '});
else{
v1.push_back(node{2,i-1,' '}),v1.push_back(node{2,i,' '});
if(str[i-1]!=c){
v1.push_back({2,i-1,' '});
}else{
i--;
}
}
}
//
swap(b,c);
v2.push_back(node{1,-1,a});
s2+=a;
v2.push_back(node{1,-1,b});
s2+=b;
for(int i=3;i<=n;i++){
v2.push_back(node{1,0,c});
v2.push_back(node{2,i,' '});
if(i%2==1) s2+=a;
else s2+=b;
}
s2=" "+s2;
for(int i=n;i>=2;i--){
if(s2[i]==str[i]) continue;
else if(str[i]==c) v2.push_back(node{2,i,' '});
else{
v2.push_back(node{2,i-1,' '}),v2.push_back(node{2,i,' '});
if(str[i-1]!=c){
v2.push_back({2,i-1,' '});
}else{
i--;
}
}
}
//
if(v1.size()<v2.size()) v=v1;
else v=v2;
cout<<v.size()<<"\n";
for(int i=0;i<v.size();i++){
if(v[i].t==1) cout<<1<<" "<<v[i].ch<<"\n";
else cout<<2<<" "<<v[i].id<<"\n";
}
return 0;
}
时间复杂度为线性,但是常数大,卡卡常应该可以拿最优解。