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

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;
}
1079(wypx)

s:=wow=,点兔的音乐太好了,害得我没法专心打oi模拟赛了

w:快把你耳机摘下来……等等我先把我耳机摘下来x

原文地址:https://www.cnblogs.com/ck666/p/7436167.html