帶延遲的動態規劃--51nod1327棋盤遊戲
阿新 • • 發佈:2018-12-15
傳送門 看到資料範圍就覺得這一定是一個或者的 果然是這樣,因為每一列都是填一個或者不填,所以一定是按列
但這個和以往有些不同,一般狀態設計都只跟當前狀態有關,並不關心前面的和後面的,但因為這道題中有一些不同,噹噹前列舉的列數不斷增大時,有一些之前可以填的到後面就不能填了,但只要當前能填,後面就一直能填
所以就有了帶延遲的動態規劃: 也就是說我們可以把當前可以處理但卻沒有處理的狀態記下來,到後面因為某些限制而必須處理的時候再處理
設表示當前處理到列,前面空下了列,當前可以處理的有個沒有處理的方案數,當我們還沒有碰到某個的邊界,就不會填,只有碰到的邊界的時候,再從前面空下的列中找一列填上,這個可以用排列計算;而對於,只要碰到了邊界,我們就可以選擇處理或者不處理;當然這一列還可以選擇不填或者填在中間的那一段,也就是既不在裡,也不再裡的
而且對這個狀態從向轉移很不好寫,還需要很多東西,我們可以從轉移到它能夠轉移的狀態去
程式碼如下:
#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
*/