题意:
给你一个串,现在让你翻转一个子串,使得串内所有元素不同的子串最长。问你长度是多少。
题解:
首先我们发现,所谓翻转子串,其实就是让你找到两个不重叠子串,使得他们没有一个元素相同并且最长。
那么这道题就非常好做了,而且它告诉你只会出现20种字符,好像是在暗示着什么。那么首先想到状压,然后不重复出现的话,我们就可以想到枚举每个位置,然后暴力枚举所有长度,因为不会超过20,这样记录下所有状态的长度之后,用sosdp去做出状态s的子状态中最长是多少,这样就将子状态转移了。那么最后我们再暴力枚举一遍,然后检查总状态(1<<20)-1异或上当前状态时候的dp值是多少即可。
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5,M=1<<20;
int dp[M];
char s[N];
int main()
{
scanf("%s",s+1);
int len=strlen(s+1);
for(int i=1;i<=len;i++){
int f=0,sum=0;
for(int j=i;j<=len;j++){
int now=s[j]-'a';
if(f&(1<<now))
break;
f|=(1<<now);
sum++;
}
dp[f]=sum;
}
int mx=1<<20;
for(int i=1;i<mx;i++)
for(int j=0;j<20;j++)
if(i&(1<<j))
dp[i]=max(dp[i],dp[i^(1<<j)]);
int ans=dp[mx-1];
for(int i=1;i<=len;i++){
int f=0,sum=0;
for(int j=i;j<=len;j++){
int now=s[j]-'a';
if(f&(1<<now))
break;
f|=(1<<now);
sum++;
ans=max(ans,dp[(mx-1)^f]+sum);
}
}
printf("%d\n",ans);
return 0;
}