zoukankan      html  css  js  c++  java
  • FZU

    FZU - 2218 Simple String Problem

      题目大意:给一个长度为n含有k个不同字母的串,从中挑选出两个连续的子串,要求两个子串中含有不同的字符,问这样的两个子串长度乘积最大是多少?

       根据题目所给的k<=16很自然的想到用状压dp来处理,但不知道该dp个什么,在观摩大佬的做法后才明白。我们用0000000000000000到1111111111111111表示pomnlkjhgfedcba的字符存不存在的状态,某个字符存在的话对应位就是1,反之就是0。一开始dp[x]就表示,在给出的串中状态x的最长长度,这样很好的处理重复的字符了,比如像aab,abaab,ab,ba这些串,他们的状态都是3(也就是a位和b位是1其他全0),然后dp[3]就是5(abaab这个)。所以我们遍历一遍S的所有子串就可以得到所有状态在子串中的最长长度。

      因为是两个含有不同字符的子串长度相乘,假设目前k是4,然后一个子串是的状态是1001,那么和它含有不同字符的子串的状态分别是0010,0100,0110,也就是1001反状态0110的所有子状态,我们直接让dp[x]去和它所有反状态的子状态相乘的话就会有很多种组合,处理上就非常的麻烦,所以这时就有个优化,让dp[x]表示它和它子串中最长的长度,也就是1001,包含了0001,1000,1001这几种状态的情况,然后在判断答案时直接让dp[x]和它的反状态dp[(1<<k)-1-i](全1减去x)相乘就包含了它们各自子串的情况。具体的细节如代码。

      

     1 #include<cstdio>
     2 #include<algorithm>
     3 using namespace std;
     4 const int N=(1<<16)+18;
     5 int dp[N];
     6 char s[2118];
     7 int main()
     8 {
     9     int n,k,t;
    10     scanf("%d",&t);
    11     while(t--)
    12     {
    13         scanf("%d%d",&n,&k);
    14         scanf("%s",s);
    15         for(int i=0;i<(1<<k);i++)
    16             dp[i]=0;//初始化所有状况的初始最长长度 
    17         for(int i=0;i<n;i++)//遍历所有子串的状态 
    18         {
    19             int x=0;
    20             for(int j=i;j<n;j++)
    21             {
    22                 x|=1<<(s[j]-'a');//因为每个字符不管它在这个子串中重复出现了几次
    23                 //只要出现了一次,对于位置就是1,所以直接对位与| 
    24                 dp[x]=max(dp[x],j-i+1);
    25             }
    26         }
    27         for(int i=0;i<(1<<k);i++)//让每个状态包含它的子状态 
    28             for(int j=0;j<k;j++)
    29                 if(i&(1<<j))//对位是1的异或取反 
    30                     dp[i]=max(dp[i],dp[i^(1<<j)]);
    31         //因为像10110包含了10100的状态,而10100已经包含了10000和00100
    32         //所以只需要有1的位置对位异或,10110就能包含它所有子串的状态 
    33         int ans=0;
    34         for(int i=0;i<(1<<k);i++)
    35             ans=max(ans,dp[i]*dp[(1<<k)-1-i]);//一个串的结果和它相反串的结果相乘 
    36         printf("%d
    ",ans);
    37     }
    38     return 0;
    39 }
    状压状压hashaki
  • 相关阅读:
    jQuery选择器
    js创建对象的几种方式
    call()和apply()
    js实现二分查找
    关于HTTP请求
    node/npm命令收集
    微信H5开发笔记——记录开发中用到的知识(手机摇动、事件捕获、wechat禁止分享、正则、promise...)
    css额外学习笔记
    gulp 结构和运行步骤——笔记1
    手机版H5开发--收集大神们的笔记
  • 原文地址:https://www.cnblogs.com/LMCC1108/p/10523314.html
Copyright © 2011-2022 走看看