Codeforces 1234 F Yet Another Substring Reverse —— SOSDP

This way

题意:

给你一个串,现在让你翻转一个子串,使得串内所有元素不同的子串最长。问你长度是多少。

题解:

首先我们发现,所谓翻转子串,其实就是让你找到两个不重叠子串,使得他们没有一个元素相同并且最长。
那么这道题就非常好做了,而且它告诉你只会出现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;
}

发布了530 篇原创文章 · 获赞 31 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/tianyizhicheng/article/details/104233264