1. 程式人生 > >帶延遲的動態規劃--51nod1327棋盤遊戲

帶延遲的動態規劃--51nod1327棋盤遊戲

傳送門 看到資料範圍就覺得這一定是一個n2mn^2*m或者nm2n*m^2dpqwqdp\ qwq 果然是這樣,因為每一列都是填一個或者不填,所以一定是按列dpdp

但這個dpdp和以往有些不同,一般dpdp狀態設計都只跟當前狀態有關,並不關心前面的和後面的,但因為這道題中liril_i和r_i有一些不同,噹噹前列舉的列數ii不斷增大時,有一些之前可以填的ll到後面就不能填了,但rr只要當前能填,後面就一直能填..

所以就有了帶延遲的動態規劃: 也就是說我們可以把當前可以處理但卻沒有處理的狀態記下來,到後面因為某些限制而必須處理的時候再處理

f[i][j][k]f[i][j][k]表示當前處理到ii列,前面空下了jj列,當前可以處理的rrkk個沒有處理的方案數,當我們還沒有碰到某個ll的邊界,就不會填,只有碰到ll的邊界的時候,再從前面空下的jj列中找一列填上,這個可以用排列計算;而對於rr,只要碰到了邊界,我們就可以選擇處理或者不處理;當然這一列還可以選擇不填或者填在l,rl,r中間的那一段,也就是既不在ll裡,也不再rr裡的..

而且對這個狀態從i1i-1ii轉移很不好寫,還需要很多東西,我們可以從ii轉移到它能夠轉移的狀態去

程式碼如下:

#include<iostream>
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #define N 55 #define M 205 #define LL long long using namespace std; int n,m,l[N],r[N],al[M],ar[M],cl,cr,tot; LL f[M][M][N],fac[M],inv[M],ans; const int mod=1e9+7; inline int rd(){ int x=0,f=1;char c=' ';
while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar(); while(c<='9' && c>='0') x=x*10+c-'0',c=getchar(); return x*f; } inline LL qpow(LL x,int k){ LL ret=1; while(k){ if(k&1) (ret*=x)%=mod; (x*=x)%=mod; k>>=1; } return ret; } inline void pre(){ fac[1]=1; for(int i=2;i<=m+1;i++) fac[i]=fac[i-1]*i%mod; inv[m+1]=qpow(fac[m+1],mod-2); for(int i=m+1;i;i--) inv[i-1]=inv[i]*i%mod; } inline LL P(int n,int m){ if(m==0) return 1; if(n<m) return 0; // if(n==m) return 1;多加了這個特判wa了一次我怕不是個zz return fac[n]*inv[n-m]%mod; } inline void add(LL &x,LL y){ x+=y; x>=mod?x-=mod:0; } int main(){ n=rd(); m=rd(); for(int i=1;i<=n;i++) l[i]=rd(),r[i]=rd(),al[l[i]]++,ar[m-r[i]+1]++; pre(); f[1][0][0]=1; for(int i=1;i<=m;i++){ tot+=al[i-1]-ar[i]; for(int j=max(0,al[i]-1);j<=i-1-cl;j++) for(int k=0;k<=cr;k++){ if(!f[i][j][k]) continue; if(al[i])//i這一列填在l上 add(f[i+1][j-al[i]+1][k+ar[i]],f[i][j][k]*P(j,al[i]-1)%mod*al[i]%mod); if(k+ar[i] && j>=al[i])//i這一列填在r上,注意這裡是k+ar[i] add(f[i+1][j-al[i]][k+ar[i]-1],f[i][j][k]*P(j,al[i])%mod*(k+ar[i])%mod); if(tot && j>=al[i])//i這一列填在既不是l也不是r的位置上 add(f[i+1][j-al[i]][k+ar[i]],f[i][j][k]*P(j,al[i])%mod*tot%mod); if(j>=al[i])//i這一列空下 add(f[i+1][j-al[i]+1][k+ar[i]],f[i][j][k]*P(j,al[i])%mod); } cl+=al[i]; cr+=ar[i]; } for(int i=0;i<=m;i++) (ans+=f[m+1][i][0])%=mod; printf("%lld\n",ans); return 0; } /* 3 7 1 2 4 3 2 1 */