bzoj 1079: [SCOI2008]着色方案
1079: [SCOI2008]着色方案
2017-08-26
Description
有n个木块排成一行,从左到右依次编号为1~n。你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块。
所有油漆刚好足够涂满所有木块,即c1+c2+...+ck=n。相邻两个木块涂相同色显得很难看,所以你希望统计任意两
个相邻木块颜色不同的着色方案。
Input
第一行为一个正整数k,第二行包含k个整数c1, c2, ... , ck。
Output
输出一个整数,即方案总数模1,000,000,007的结果。
Sample Input
3
1 2 3
1 2 3
Sample Output
10
HINT
100%的数据满足:1 <= k <= 15, 1 <= ci <= 5
一开始想按照某鳖棋那样子暴力的,一共开15维。。(肯定不对的说,时间空间都不对);
那看ci<=5what?数字蛮小的的说,那就可以枚举每个染料的个数。
前五维是每一个颜料剩余i的颜色总个数;最后一维是上一次染色。
总之很玄学。
#include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #define ll long long using namespace std; const ll mod=1000000007; int a[10],n,t; ll dp[16][16][16][16][16][6]; bool rem[16][16][16][16][16][6]; ll F(int a,int b,int c,int d,int e,int k){ if(a+b+c+d+e==0){ rem[a][b][c][d][e][k]=dp[a][b][c][d][e][k]=1;return 1;} if(dp[a][b][c][d][e][k])return dp[a][b][c][d][e][k]; ll t=0; if(a)t+=(a-(k==2))*F(a-1,b,c,d,e,1); if(b)t+=(b-(k==3))*F(a+1,b-1,c,d,e,2); if(c)t+=(c-(k==4))*F(a,b+1,c-1,d,e,3); if(d)t+=(d-(k==5))*F(a,b,c+1,d-1,e,4); if(e)t+=(e)*F(a,b,c,d+1,e-1,5); rem[a][b][c][d][e][k]=1;dp[a][b][c][d][e][k]=t%mod; return t%mod; } int main(){ cin>>n; for(int i=1;i<=n;i++){cin>>t;a[t]++;} cout<<F(a[1],a[2],a[3],a[4],a[5],0)%mod; return 0; }
by:s_a_b_e_r
最近s同学学会了读入优化
还没看题先开始写读入优化
于是看到数据范围之后……ww
一开始各种瞎想……组合数?容斥?
想不出来.jpg
后来看了题解,记忆化搜索
因为如果两种油漆剩余使用次数一样的话,可以看做等效的说
f[a][b][c][d][e][l]表示剩余1次的油漆有a种……剩余5次的油漆有e种,l表示上次涂的颜色
如果上一次用的是l油漆,这一次就不能再涂l油漆
于是就有了这个神奇的转移方程
#include<iostream> #include<cstdio> using namespace std; const int M=1000000007; int k,c[10]; long long f[16][16][16][16][16][6]; long long dp(int a,int b,int c,int d,int e,int l) { if(a+b+c+d+e==0)return 1; if(f[a][b][c][d][e][l])return f[a][b][c][d][e][l]; long long t=0; if(a)t+=(a-(l==2))*dp(a-1,b,c,d,e,1); if(b)t+=(b-(l==3))*dp(a+1,b-1,c,d,e,2); if(c)t+=(c-(l==4))*dp(a,b+1,c-1,d,e,3); if(d)t+=(d-(l==5))*dp(a,b,c+1,d-1,e,4); if(e)t+=e*dp(a,b,c,d+1,e-1,5); f[a][b][c][d][e][l]=t%M; return f[a][b][c][d][e][l]; } int main() { cin>>k; int x; for(int i=1;i<=k;++i){cin>>x;++c[x];} long long ans=dp(c[1],c[2],c[3],c[4],c[5],0)%M; cout<<ans<<endl; return 0; }
s:=wow=,点兔的音乐太好了,害得我没法专心打oi模拟赛了
w:快把你耳机摘下来……等等我先把我耳机摘下来x