总结
问题:构造一个最小颜色数量的字符串
子问题:构造一个只有两种颜色的字符串
情况1:只需要一种颜色字符串就满足
说明这个字符串本身就是一个非严格递增字符串,字符串全为0
情况2:只需要两种颜色字符串就满足
说明就是两种颜色的字符串本身就是一个非严格递增的字符串,这样做交换,只是每次交换都是最优的。
举例:
s1=abcd
s2=acd;
两个字符串合并
s2的第一个字符,其实也可以一步的
abcd-acd
abcad-cd
abacd-cd
aabcd-cd
s2的第二个字符
aabcdc-d
aabccd-d
s3的第三个字符
aabccdd
情况3:大于两种的,为了构造最长的两种颜色,我们肯定两个最长非严格递增序列,如果还达不到n,就输出no
构造最小颜色数量字符串
ans=0;
先构造一个最长非严格递减序列,ans++;
再在剩下的序列构造一个最长的非严格递减序列,ans++;
直到构造完
DP
这里为啥dp开26就可以了,max(ans)=26,为什么?
每种字母取一种颜色,就是26种颜色,ans最大是26,题目要求min,
const int N=2e5+5;
int dp[26];
signed main()
{
IOS;
//file();
int n,num=0;
string str;
vector<int>ans;
cin>>n>>str;
for(int i=0;i<n;i++)
{
for(int j=0;j<26;j++)
{
if(dp[j]<=str[i])
{
dp[j]=str[i];
ans.pb(j+1);
num=max(num,j+1);
break;
}
}
}
cout<<num<<endl;
for(auto it:ans)
cout<<it<<" ";
cout<<endl;
return 0;
}
二分
由于二分函数,只能求单调非严格递增数组,所以我们求最长非严格递增序列,倒着求最长非严格递减序列,二维就是的X轴就是一个最长非严格递减序列,但是Y轴就是一个最长非严格递增序列,方便调用内部函数,当然可以自己手打,不用这么麻烦
signed main()
{
IOS;
//file();
int n,num=0;
string str;
vector<int>ans,vec;
cin>>n>>str;
reverse(all(str));
for(int i=0;i<n;i++)
{
int pos=lower_bound(all(vec),str[i])-vec.begin();
ans.pb(pos+1);
num=max(num,pos+1);
if(pos<vec.size())
vec[pos]=str[i];
else
vec.pb(str[i]);
}
cout<<num<<endl;
reverse(all(ans));
for(auto it:ans)
cout<<it<<" ";
cout<<endl;
return 0;
}