1. 程式人生 > >$[ SCOI 2008 ] $ 著色方案

$[ SCOI 2008 ] $ 著色方案

++ algo 超時 做的 string += 答案 iostream line


\(\\\)

\(Description\)


給出\(K\)種顏料各自的個數\(C_i\),每一個顏料只夠塗一個格子,求將顏料用完,塗一排格子,每個格子只能塗一次的條件下,相鄰兩個格子的顏色互不相同的方案數對\(10^9+7\)取模的結果。

  • \(K\in [1,15]\)\(C_i\in [1,5]\)

\(\\\)

\(Solution\)


想的map壓縮狀態量記搜掛了

想的容斥記搜求組合數排列數取反掛了

正解真是神仙計數題做的還是少,基本的思路模型還是沒有。

  • 註意到顏色相同的顏料性質是一致的。
  • 基於開始想的兩種方案狀態量太大,記搜也會超時,而將一類顏料看作一種之後,狀態量大大減少,相當於只有\(5\)
    種顏料,狀態裏還需記錄上一個顏料屬於哪一類即可。
  • 設計狀態\(f[n_1][n_2][n_3][n_4][n_5][last]\)表示,剩余個數分別為\(1\text~5\)的顏料各有幾個,上一次使用的顏料使用前剩幾個,此時到用完所有顏料的總塗色方案數。
  • 搜起來就很簡單啦,直接考慮搜哪一位遞歸下去,到全是\(0\)了答案就是\(1\),搜完累計答案時,因為一類顏料是相同的,所以直接乘上該決策的可行顏料個數。
  • 一些就我會犯的zz錯誤細節要註意:
    • 優先判斷搜索的顏料還有沒有再考慮搜沒搜到過,否則會數組越界
    • 註意到狀態設計是使用前剩幾個所以判斷可行顏料個數時,判斷時應該是上一個是否是當前\(+1\)
      而不是是否相同,因為你拿了一次個數一定減了一個\(1\)
    • \(+1-1\)的時候註意是成對存在的不要光顧著-1
  • 這樣搜索的優越性在於,他的狀態量少,代表性強,只關心相同性質的數的個數,與一些問題的精簡狀態量思想異曲同工但就是想不到在這裏用

\(\\\)

\(Code\)


#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define R register
#define gc getchar
#define mod 1000000007ll
using namespace std;
typedef long long ll;
 
inline ll rd(){
  ll x=0; bool f=0; char c=gc();
  while(!isdigit(c)){if(c=='-')f=1;c=gc();}
  while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
  return f?-x:x;
}
 
ll n,s[10],f[16][16][16][16][16][10];
 
void dfs(ll n1,ll n2,ll n3,ll n4,ll n5,ll lst){
  if((n1|n2|n3|n4|n5)==0ll){f[0][0][0][0][0][lst]=1ll;return;}
  if(n1>0ll&&!f[n1-1][n2][n3][n4][n5][1]) dfs(n1-1,n2,n3,n4,n5,1);
  if(n2>0ll&&!f[n1+1][n2-1][n3][n4][n5][2]) dfs(n1+1,n2-1,n3,n4,n5,2);
  if(n3>0ll&&!f[n1][n2+1][n3-1][n4][n5][3]) dfs(n1,n2+1,n3-1,n4,n5,3);
  if(n4>0ll&&!f[n1][n2][n3+1][n4-1][n5][4]) dfs(n1,n2,n3+1,n4-1,n5,4);
  if(n5>0ll&&!f[n1][n2][n3][n4+1][n5-1][5]) dfs(n1,n2,n3,n4+1,n5-1,5);
  if(n2>0ll) (f[n1][n2][n3][n4][n5][lst]+=(n2-(lst==3))*f[n1+1][n2-1][n3][n4][n5][2])%=mod;
  if(n3>0ll) (f[n1][n2][n3][n4][n5][lst]+=(n3-(lst==4))*f[n1][n2+1][n3-1][n4][n5][3])%=mod;
  if(n4>0ll) (f[n1][n2][n3][n4][n5][lst]+=(n4-(lst==5))*f[n1][n2][n3+1][n4-1][n5][4])%=mod;
  if(n1>0ll) (f[n1][n2][n3][n4][n5][lst]+=(n1-(lst==2))*f[n1-1][n2][n3][n4][n5][1])%=mod;
  if(n5>0ll)(f[n1][n2][n3][n4][n5][lst]+=n5*f[n1][n2][n3][n4+1][n5-1][5])%=mod;
}
 
int main(){
  n=rd();
  for(R ll i=1;i<=n;++i) ++s[rd()];
  dfs(s[1],s[2],s[3],s[4],s[5],6);
  printf("%lld\n",f[s[1]][s[2]][s[3]][s[4]][s[5]][6]);
  return 0;
}

$[\ SCOI\ 2008\ ]\ $ 著色方案