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\n",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\n",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\n",ans[i]); 77 return 0; 78 }