1. 程式人生 > >bzoj 1079: [SCOI2008]著色方案

bzoj 1079: [SCOI2008]著色方案

我沒 組合 滿足 b- col line 模擬 lose 同學

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

bzoj 1079: [SCOI2008]著色方案