$bzoj1079-SCOI2008$ 著色方案
阿新 • • 發佈:2019-05-09
lin 行為 記憶 != 題意 return ems zoj -s
- 題面描述
- 有\(n\)個木塊排成一行,從左到右依次編號為\([1,n]\)。你有\(k\)種顏色的油漆,其中第\(i\)種顏色的油漆足夠塗\(c_i\)個木塊。所有油漆剛好足夠塗滿所有木塊,即\(\sum_{i=1}^k c_i=n\)。相鄰兩個木塊塗相同色顯得很難看,所以你希望統計任意兩個相鄰木塊顏色不同的著色方案。
- 輸入格式
- 第一行為一個正整數\(k\),第二行包含\(k\)個整數\(c_1, c_2, ... , c_k\)。
- 輸出格式
- 輸出一個整數,即方案總數模\(1e9+7\)的結果。
- 題解
- 根據題意可寫出暴力\(dp\),\(f_{i,5,5,\cdots\,5,x}\)
- 但是我們其實並不需要記錄每個色有多少個,我們只需要記錄當前顏色有\(1,2,3,4,5\)個各有幾個,\(f_{i,a_1,a_2,a_3,a_4,a_5,x}\)用記憶化搜索即可
- 根據題意可寫出暴力\(dp\),\(f_{i,5,5,\cdots\,5,x}\)
- 備註
- 用正常方法做,會有很多冗余狀態,不能直接用\(cnt_i\)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const ll mod=1e9+7; ll f[16][16][16][16][16][6]; bool use[16][16][16][16][16][6]; int n; int cnt[6]; ll dp(int a,int b,int c,int d,int e,int x){ if (use[a][b][c][d][e][x]) return f[a][b][c][d][e][x]; if (a+b+c+d+e==0) return 1; ll ret=0; if (a>0) ret=(ret+(a-(x==2))*dp(a-1,b,c,d,e,1)%mod)%mod; if (b>0) ret=(ret+(b-(x==3))*dp(a+1,b-1,c,d,e,2)%mod)%mod; if (c>0) ret=(ret+(c-(x==4))*dp(a,b+1,c-1,d,e,3)%mod)%mod; if (d>0) ret=(ret+(d-(x==5))*dp(a,b,c+1,d-1,e,4)%mod)%mod; if (e>0) ret=(ret+e*dp(a,b,c,d+1,e-1,5)%mod)%mod; use[a][b][c][d][e][x]=1; return f[a][b][c][d][e][x]=ret%mod; } int main(){ scanf("%d",&n); for (int i=1;i<=n;i++){ int x; scanf("%d",&x); cnt[x]++; } // memset(f,-1,sizeof(f)); printf("%lld\n",dp(cnt[1],cnt[2],cnt[3],cnt[4],cnt[5],0)); return 0; }
- 附一個錯誤的順序\(dp\)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN=76; int n,cnt[10],tot; int f[3][16][16][16][16][16][6]; int main(){ scanf("%d",&n); for (int i=1;i<=n;i++){ int x; scanf("%d",&x); cnt[x]++; tot+=x; } n=tot; f[1][cnt[1]-1][cnt[2]][cnt[3]][cnt[4]][cnt[5]][1]=cnt[1]; f[1][cnt[1]+1][cnt[2]-1][cnt[3]][cnt[4]][cnt[5]][2]=cnt[2]; f[1][cnt[1]][cnt[2]+1][cnt[3]-1][cnt[4]][cnt[5]][3]=cnt[3]; f[1][cnt[1]][cnt[2]][cnt[3]+1][cnt[4]-1][cnt[5]][4]=cnt[4]; f[1][cnt[1]][cnt[2]][cnt[3]][cnt[4]+1][cnt[5]-1][5]=cnt[5]; for (int i=2;i<=n;i++){ for (int j=0;j<=15;j++){ for (int k=0;k<=15;k++){ for (int l=0;l<=15;l++){ for (int m=0;m<=15;m++){ for (int r=0;r<=15;r++){ for (int x=1;x<=5;x++){ for (int y=1;y<=5;y++){ int now=i&1; int pre=now^1; if (j>0&&x==1&&x+1==y) f[now][j-1][k][l][m][r][x]+=f[pre][j][k][l][m][r][y]*(j-1); if (j>0&&x==1&&x+1!=y) f[now][j-1][k][l][m][r][x]+=f[pre][j][k][l][m][r][y]*j; if (k>0&&x==2&&x+1==y) f[now][j+1][k-1][l][m][r][x]+=f[pre][j][k][l][m][r][y]*(k-1); if (k>0&&x==2&&x+1!=y) f[now][j+1][k-1][l][m][r][x]+=f[pre][j][k][l][m][r][y]*k; if (l>0&&x==3&&x+1==y) f[now][j][k+1][l-1][m][r][x]+=f[pre][j][k][l][m][r][y]*(l-1); if (l>0&&x==3&&x+1!=y) f[now][j][k+1][l-1][m][r][x]+=f[pre][j][k][l][m][r][y]*l; if (m>0&&x==4&&x+1==y) f[now][j][k][l+1][m-1][r][x]+=f[pre][j][k][l][m][r][y]*(m-1); if (m>0&&x==4&&x+1!=y) f[now][j][k][l+1][m-1][r][x]+=f[pre][j][k][l][m][r][y]*m; if (r>0&&x==5&&x+1==y) f[now][j][k][l][m+1][r-1][x]+=f[pre][j][k][l][m][r][y]*(r-1); if (r>0&&x==5&&x+1!=y) f[now][j][k][l][m+1][r-1][x]+=f[pre][j][k][l][m][r][y]*r; } } } } } } } } int ans=0; for (int i=0;i<=15;i++){ for (int j=0;j<=15;j++){ for (int k=0;k<=15;k++){ for (int l=0;l<=15;l++){ for (int m=0;m<=15;m++){ for (int x=1;x<=5;x++){ ans+=f[n&1][i][j][k][l][m][x]; } } } } } } printf("%d\n",ans); return 0; }
$bzoj1079-SCOI2008$ 著色方案