bzoj-1079 着色方案(dp)
Time Limit:10000MS Memory Limit:165888KB
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
Sample Output
10
Hint
100%的数据满足:1 <= k <= 15, 1 <= ci <= 5
题意:
思路:
f[a][b][c][d][e][x]表示能涂一个格子的油漆有a种,能涂两个格子的油漆有b种...x表示的是上一次涂的是能涂x个格子的油漆;
f[a][b][c][d][e][x]=f[a-1][b][c][d][e]*(a-(x==2))+f[a+1][b-1][c][d][e]*(b-(x==3))+...+f[a][b][c][d+1][e-1]*(a-(x==6));
这个方程表示,剩下a,b,c,d,e,上次的是x,
假设这次要用可以涂k个格子的油漆,那么涂完这个格子,可以涂k个格子的油漆少了一种,可以涂k-1个格子的油漆多了一种;
这就是为什么b-1的时候a+1,c-1的时候b+1的原因;
还有就是相邻的格子的颜色不同,假设上一次用的是可以涂x个格子的油漆,那么上一次用完后的那种油漆就变成了一种可以涂x-1个格子的油漆了,那么这一次再选油漆的时候就不能再选可以涂x-1个格子的油漆的一种(这种上次一就用过了);所以对应的是*(a-(x==2))和*(b-(x==3))这些了;
AC代码:
//#include <bits/stdc++.h> #include <vector> #include <iostream> #include <queue> #include <cmath> #include <map> #include <cstring> #include <algorithm> #include <cstdio> using namespace std; #define For(i,j,n) for(int i=j;i<=n;i++) #define mst(ss,b) memset(ss,b,sizeof(ss)); typedef long long LL; template<class T> void read(T&num) { char CH; bool F=false; for(CH=getchar();CH<'0'||CH>'9';F= CH=='-',CH=getchar()); for(num=0;CH>='0'&&CH<='9';num=num*10+CH-'0',CH=getchar()); F && (num=-num); } int stk[70], tp; template<class T> inline void print(T p) { if(!p) { puts("0"); return; } while(p) stk[++ tp] = p%10, p/=10; while(tp) putchar(stk[tp--] + '0'); putchar('\n'); } const LL mod=1e9+7; const double PI=acos(-1.0); const LL inf=1e18; const int N=2e3+10; const int maxn=1005; const double eps=1e-10; int num[7]; LL f[17][17][17][17][17][6]; LL dp(int a,int b,int c,int d,int e,int x) { if(f[a][b][c][d][e][x]!=0)return f[a][b][c][d][e][x]; LL ans=0; if(a)ans=(ans+(a-(x==2))*dp(a-1,b,c,d,e,1))%mod; if(b)ans=(ans+(b-(x==3))*dp(a+1,b-1,c,d,e,2))%mod; if(c)ans=(ans+(c-(x==4))*dp(a,b+1,c-1,d,e,3))%mod; if(d)ans=(ans+(d-(x==5))*dp(a,b,c+1,d-1,e,4))%mod; if(e)ans=(ans+e*dp(a,b,c,d+1,e-1,5))%mod; f[a][b][c][d][e][x]=ans; return ans; } int main() { int k,x; read(k); For(i,1,k)read(x),num[x]++; f[1][0][0][0][0][1]=1; cout<<dp(num[1],num[2],num[3],num[4],num[5],6)<<"\n"; return 0; }