Yet Another Substring Reverse CodeForces - 1234F 状态压缩

问题:

You are given a string ss consisting only of first 2020 lowercase Latin letters ('a', 'b', ..., 't').

Recall that the substring s[l;r]s[l;r] of the string ss is the string slsl+1…srslsl+1…sr . For example, the substrings of "codeforces" are "code", "force", "f", "for", but not "coder" and "top".

You can perform the following operation no more than once: choose some substring s[l;r]s[l;r] and reverse it (i.e. the string slsl+1…srslsl+1…sr becomes srsr−1…slsrsr−1…sl ).

Your goal is to maximize the length of the maximum substring of ss consisting of distinct (i.e. unique) characters.

The string consists of distinct characters if no character in this string appears more than once. For example, strings "abcde", "arctg" and "minecraft" consist of distinct characters but strings "codeforces", "abacaba" do not consist of distinct characters.

Input

The only line of the input contains one string ss consisting of no more than 106106 characters 'a', 'b', ..., 't' (first 2020 lowercase Latin letters).

Output

Print one integer — the maximum possible length of the maximum substring of ss consisting of distinct characters after reversing no more than one its substring.

Examples

Input

abacaba

Output

3

Input

abcdecdf

Output

6

Input                           

aabbcc

Output

3

Input

abcdeefc

Output

6

题意:给一个字符串,你可以反转任意一个子串,只能反转一次,找到一个最长不同字母子串的长度;

思路:利用二进制进行储存,a b c d e f g h i  j  k l m n o p q r s t

                                               1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

状态转移方程:maxx=max(maxx,dp[(1<<20)-1-i]+dp[i]); 

1<<20-1-i表示它的相反状态

看代码:

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
int book[1<<21],dp[1<<21];
char s[1001000];
//利用二进制解决
//a b c d e f g h i j k l m n o p q r s t
//1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
//1<<20-1-i表示它的相反状态
int main()
{
    scanf("%s",&s);
    int d=strlen(s);
    memset(dp,0,sizeof(dp));
    for(int i=0; i<d; i++)//把所有的状态都存起来
    {
        int ans=0,num=0;//ans记录状态,num记录不同字母的个数
        for(int j=i; j<d; j++)//不会超时,最多跑20次
        {
            num++;
            int k=s[j]-97;
            if(ans&(1<<k))//判断重复字母,&只会返回1或0;
                break;
            ans=ans|(1<<k);//把没有出现过的字母加进去
            dp[ans]=num;//标记这种状态;
        }
    }
    for(int i=0; i<20; i++) //为反转做处理,意思是把每一种状态没有的字母都补进去,但只是虚拟,并没有增加字母种类;
        for(int j=0; j<(1<<20); j++)
        {
            if(j&(1<<i))
                continue;
            int kk=j|(1<<i);
            dp[kk]=max(dp[kk],dp[j]);
        }
    int maxx=0;
    for(int i=0; i<(1<<20); i++)
        maxx=max(maxx,dp[(1<<20)-1-i]+dp[i]);//1<<20-1-i表示它的相反状态
    printf("%d\n",maxx);
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值