CF1234F题解
趁它还是紫题,赶紧来写一发。
题目大意
给你一个字符串
思路
首先,我们观察可以发现,对于翻转后合法的一个子串,其翻转前是两个子串,而且他们的字符互不相同,我们是不关心他们的前后顺序的。
因此,题意转化为求字符串
其次,我们观察到只有前
于是,思路就有了,我们可以将
那么我们就可以运用高维前缀和解决。
但是,除了高维前缀和,我们还可以有另一种解释。在对
时间复杂度显然是可以接受的。
于是我们就做完了。
Code
//区间翻转后,子串的字符集不会发生改变,其实就是求两个子串拼一起的最大价值
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
#define fi first
#define se second
using namespace std;
const int N=2e5+10;
const int inf=0x3f3f3f3f3f3f3f3f;
string s;
int len[1<<20];
int sum[1<<20]; //高维前缀和
int ans;
signed main()
{
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(false);
cin>>s;
for(int i=0;i<s.size();i++)
{
int da=0;
for(int j=i;j<s.size();j++)
{
if(da&(1<<(s[j]-'a'))) // 看似两层循环,实际上最多20
{
break;
}
da|=(1ll<<(s[j]-'a'));
len[da]=j-i+1;
}
}
for(int i=0;i<(1ll<<20);i++)
{
sum[i]=len[i];
}
for(int i=0;i<(1ll<<20);i++)
//高位前缀和,但还可以换个思路,实际上在统计答案时
//我当前状态的取反后的状态不一定是满的,此时它的子集也是符合要求的,也要统计,可以结合下面的代码
{
for(int j=0;j<20;j++)
{
if(i&(1ll<<j)) sum[i]=max(sum[i],sum[i^(1ll<<j)]);
}
}
for(int i=0;i<(1<<20);i++)
{
ans=max(ans,sum[((1<<20)-1)^i]+sum[i]);
}
cout<<ans;
return 0;
}