• 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]);
    }
    
  • 相关阅读:
    socket详解(二)----实例和多线程,线程池使用
    OpenJDK和JDK区别
    单词(11)
    程序员到项目经理:从内而外的提升(比较全面的介绍)
    如何成为一名自然语言处理工程师
    权限设计文章汇总
    ECharts+百度地图,默认选中 卫星地图
    Echarts3.0 引入百度地图(转载)
    echarts地图 鼠标滚动控制缩放大小比例(转载)
    echarts散点图 不显示问题 或宽度为0问题
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/13023587.html
Copyright © 2020-2023  润新知