【agc030f】Permutation and Minimum(動態規劃)
阿新 • • 發佈:2019-03-07
href true stream minimum for 一個 https lse tasks 對。
暫時不用考慮對與對之間的順序關系,最後把由兩個\(-1\)組成的配對拿出來乘一個階乘就好了。
考慮新加入的這個數。它有兩種貢獻,第一種是和一個填了一半的進行配對,另外一個是自己產生一個填了一半的配對。
分類討論,考慮它是不是\((x,-1)\)對中的一個\(x\)。
如果不是,那麽可以考慮填入一個\((-1,-1)\)對中的一個,那麽轉移到\(f[i][j+1][k]\),要麽匹配掉一個\((-1,-1)\)對,變成\(f[i][j-1][k]\),要麽匹配一個\((x,-1)\)對,這裏有\(k\)種匹配方法,所以乘\(k\)後轉移到\(f[i][j][k-1]\)。
如果是,那麽要麽不匹配,轉移到\(f[i][j][k+1]\) ,要麽拉一個填了一半的\((-1,-1)\)對過來,轉移到\(f[i][j-1][k]\)。
【agc030f】Permutation and Minimum(動態規劃)
題面
atcoder
給定一個長度為\(2n\)的殘缺的排列\(A\),定義\(b_i=min\{A_{2i-1},A_{2i}\}\),求有多少種不同的\(b\)。
題解
考慮這個\(b\)的取值是兩兩配對之後求\(min\),所以我們把所有的數按照從大往小處理,這樣子就可以在每一對數填好的時候計算貢獻。
首先把已經確定的\(b\)直接丟掉。這樣子剩下了若幹個填了一半和沒有填的對。
設\(f[i][j][k]\)表示當前考慮到第\(i\)個數,還剩下\(j\)對填了一個數的\((-1,-1)\)對和\(k\)對未匹配的\((x,-1)\)
暫時不用考慮對與對之間的順序關系,最後把由兩個\(-1\)組成的配對拿出來乘一個階乘就好了。
考慮新加入的這個數。它有兩種貢獻,第一種是和一個填了一半的進行配對,另外一個是自己產生一個填了一半的配對。
分類討論,考慮它是不是\((x,-1)\)對中的一個\(x\)。
如果不是,那麽可以考慮填入一個\((-1,-1)\)對中的一個,那麽轉移到\(f[i][j+1][k]\),要麽匹配掉一個\((-1,-1)\)對,變成\(f[i][j-1][k]\),要麽匹配一個\((x,-1)\)對,這裏有\(k\)種匹配方法,所以乘\(k\)後轉移到\(f[i][j][k-1]\)。
如果是,那麽要麽不匹配,轉移到\(f[i][j][k+1]\)
#include<iostream> #include<cstdio> using namespace std; #define MOD 1000000007 #define MAX 305 void add(int &x,int y){x+=y;if(x>=MOD)x-=MOD;} inline int read() { int x=0;bool t=false;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=true,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return t?-x:x; } int n,m,ans,a[MAX<<1]; int cnt1,cnt2,f[MAX<<1][MAX][MAX]; int S[MAX<<1]; bool vis[MAX<<1],book[MAX<<1]; int main() { n=read(); for(int i=1;i<=n+n;++i)a[i]=read(); for(int i=1;i<=n+n;i+=2) if(a[i]==-1&&a[i+1]==-1)++cnt1; else if(a[i]>0&&a[i+1]>0)vis[a[i]]=vis[a[i+1]]=true; else ++cnt2,book[(~a[i])?a[i]:a[i+1]]=true; for(int i=n+n;i;--i)if(!vis[i])S[++m]=i; f[0][0][0]=1; for(int i=1;i<=m;++i) for(int j=0;j<=cnt1+cnt2;++j) for(int k=0;k<=cnt2;++k) { if(!f[i-1][j][k])continue; if(!book[S[i]]) { add(f[i][j+1][k],f[i-1][j][k]); if(j)add(f[i][j-1][k],f[i-1][j][k]); if(k)add(f[i][j][k-1],1ll*k*f[i-1][j][k]%MOD); } else { add(f[i][j][k+1],f[i-1][j][k]); if(j)add(f[i][j-1][k],f[i-1][j][k]); } } ans=f[m][0][0];for(int i=1;i<=cnt1;++i)ans=1ll*ans*i%MOD; printf("%d\n",ans); return 0; }
【agc030f】Permutation and Minimum(動態規劃)