zoukankan      html  css  js  c++  java
  • tjoi2018D2T2(luogu4590) 游园会 (状压dp)

    题解劝退系列

    设长的那个串是A,短的那个串是B。

    那我们在如果已经知道某个A的时候,A[1..i]和B[1..j]的最长公共子序列$f[i][j]=max{f[i-1][j],f[i][j-1],f[i-1][j-1]+(A[i]==B[i])}$

    于是可以递推来枚举A,顺手把NOI的情况判掉。但这复杂度显然过不了。

    注意到在推的时候,每新加一个字符,就可以由f[i-1]推出f[i],也就是说,我们根本不用记递推出来的这个A具体是什么,只要记住这个f[i]就可以了。

    怎么记呢?注意到f[i][j]只能等于f[i][j-1]或者f[i][j-1]+1,也就是说,我们可以先差分这个f[i],然后状压就能记下来了。

    设trans[s][k]表示原本f数组状态是s、新加了一个k字符,转移到的状态

    那么可以得到递推式$g[i+1][trans[s][k]]=sum{g[i][s]}$,g[N][s]就是最后状态s的情况数,只要统计一下s中1的个数,记到答案里就行了。

    然而还要判NOI

    其实很简单,只要给g多记一维,用来表示现在这个状态已经匹配到了NOI的几位就可以了

    (0,1,2通过"N"转移到1;1通过“O”转移到2;2通过“I”转移到3(这个情况不合法))

    要开滚动数组

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<vector>
     5 #include<queue>
     6 #include<map>
     7 #include<cmath>
     8 #include<ctime>
     9 #include<set>
    10 #define pa pair<int,int>
    11 #define lowb(x) ((x)&(-(x)))
    12 #define REP(i,n0,n) for(i=n0;i<=n;i++)
    13 #define PER(i,n0,n) for(i=n;i>=n0;i--)
    14 #define MAX(a,b) ((a>b)?a:b)
    15 #define MIN(a,b) ((a<b)?a:b)
    16 #define CLR(a,x) memset(a,x,sizeof(a))
    17 #define rei register int
    18 using namespace std;
    19 const int maxn=1010,maxk=16,maxs=32768,p=1e9+7;
    20 typedef long long ll;
    21 
    22 ll rd(){
    23     ll x=0;char c=getchar();int neg=1;
    24     while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
    25     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    26     return x*neg;
    27 }
    28 
    29 int N,K,M;
    30 int wd[maxk],ans[maxk],ne[3][3];
    31 int f[2][maxs][3],trans[maxs][3],cnt[maxs];
    32 
    33 inline void modadd(int &x,int y){x=(x+y)%p;}
    34 
    35 int main(){
    36     //freopen(".in","r",stdin);
    37     rei i,j,k,l;
    38     N=rd(),K=rd();M=1<<K;
    39     i=0;while(i<K){
    40         char c=getchar();
    41         if(c=='N') wd[++i]=0;
    42         else if(c=='O') wd[++i]=1;
    43         else if(c=='I') wd[++i]=2;
    44     }
    45     REP(i,0,M-1){
    46         REP(j,0,2){
    47             int s=0,sum=0,lst=0,now=0;
    48             REP(k,1,K){
    49                 if(wd[k]==j) now=sum+1;
    50                 if(i&(1<<(k-1))) sum++;
    51                 if(wd[k]!=j) now=sum;
    52                 s+=(now>lst)<<(k-1);lst=MAX(lst,now);
    53             }trans[i][j]=s;cnt[i]=sum;
    54         //printf("%d %d %d %d
    ",i,j,s,sum);
    55         }
    56     }
    57     ne[1][1]=2;ne[0][0]=ne[1][0]=ne[2][0]=1;
    58     bool b=0;f[0][0][0]=1;
    59     REP(i,0,N-1){
    60         //memcpy(f[b],f[b^1],sizeof(f[b]));
    61         CLR(f[b^1],0);
    62         REP(j,0,M-1){
    63             REP(l,0,2){if(!f[b][j][l]) continue;
    64                 REP(k,0,2){
    65                     if(l==2&&k==2) continue;
    66                     modadd(f[b^1][trans[j][k]][ne[l][k]],f[b][j][l]);
    67                     //printf("f[%d][%d][%d]=%d -%d> ",i,j,l,f[b][j][l],k);
    68                 //    printf("f[%d][%d][%d]=%d
    ",i+1,trans[j][k],ne[l][k],f[b^1][trans[j][k]][ne[l][k]]);
    69                 }
    70             }
    71         }b^=1;
    72     }
    73     REP(i,0,M-1){
    74         REP(j,0,2)
    75             modadd(ans[cnt[i]],f[b][i][j]);
    76     }REP(i,0,K) printf("%d
    ",ans[i]);
    77     return 0;
    78 }
  • 相关阅读:
    预备知识
    开场白
    H.264 / MPEG-4 Part 10 White Paper-翻译
    H.264简介
    batchGetAnchorLevel(dubbo接口)
    【Python022--递归】
    【python021-函数lambda表达式】
    【Python020--内嵌函数和闭包】
    【Python019--函数与过程】
    【python018--函数参数】
  • 原文地址:https://www.cnblogs.com/Ressed/p/9599409.html
Copyright © 2011-2022 走看看