zoukankan      html  css  js  c++  java
  • Luogu P4590 [TJOI2018]游园会

    Link
    求LCS有一个显然的(O(n^2))的dp做法,即设(f_{i,j})表示(s_i,t_j)的lcs长度,那么(f_{i,j}=max(f_{i-1,j},f_{i,j-1},f_{i-1,j-1}+[s_i=t_j]))
    (t)是题目给定的,因此在已知(f_{i-1},s_i)的情况下我们是可以求出(f_i)的。
    因此我们考虑将(f_i)当做是一个状态并把它放在自动机上,那么根据转移方程我们就可以的得到自动机上的转移进而求出答案。
    同时我们知道(f_i)是单调不降的,且相邻两项的差要么为(0)要么为(1),因此我们可以用(Delta f_i)来表示(f_i),这样自动机上的点数就只有(2^m)了。
    而且LCS的长度就是(Delta f_i)(1)的个数,这样我们就可以方便地统计了。
    然后设(f_{i,j,k})为长度为(i)的字符串,在自动机上(j)号点,匹配( ext{NOI})长度为(k)时的方案数,预处理出自动机上的转移,然后滚掉(i)这一维即可。

    #include<cstdio>
    #include<cstring>
    const int P=1000000007;const char ccf[]="NOI";
    int f[2][1<<15|1][3],trans[1<<15|1][3],ans[16];char str[16];
    void inc(int&a,int b){a+=b-P,a+=a>>31&P;}
    int main()
    {
        int n,m,now=0;
        scanf("%d%d%s",&n,&m,str),f[0][0][0]=1;
        for(int i=0;i<1<<m;++i)
    	for(int j=0;j<3;++j)
    	{
    	    int las=-1,to=i;
    	    for(int k=m-1;~k;--k) if(i>>k&1) las=k; else if(str[k]==ccf[j]) (~las? to^=1<<las:0),las=k,to^=1<<k;
    	    trans[i][j]=to;
    	}
        for(int i=1;i<=n;++i,now^=1)
        {
    	memset(f[now^1],0,sizeof f[now^1]);
    	for(int j=0;j<1<<m;++j) for(int k=0;k<3;++k) if(f[now][j][k]) for(int l=0;l<3;++l) if(k^2||l^2) inc(f[now^1][trans[j][l]][k==l? k+1:!l],f[now][j][k]);
        }
        for(int i=0;i<1<<m;++i) for(int j=0;j<3;++j) inc(ans[__builtin_popcount(i)],f[now][i][j]);
        for(int i=0;i<=m;++i) printf("%d
    ",ans[i]);
    }
    
  • 相关阅读:
    Emulator PANIC: Could not open: AVD2.3.1
    VC++ 6.0 快捷键
    eclipse 中文版 变成 英文版 方法
    SharedPreferences 用法
    subString
    Android键盘属性
    【Android异常】The specified child already has a parent. You must call removeView() on the child's parent first.
    ListView的ScrollListener
    Android 自定义格式的对话框
    Android ListView 设置
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/13023587.html
Copyright © 2011-2022 走看看