博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[ SCOI 2008 ] 着色方案
阅读量:4672 次
发布时间:2019-06-09

本文共 2286 字,大约阅读时间需要 7 分钟。

\(\\\)


给出\(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
#include
#include
#include
#include
#include
#include
#define R register#define gc getchar#define mod 1000000007llusing 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;}

转载于:https://www.cnblogs.com/SGCollin/p/9610120.html

你可能感兴趣的文章
利用jsonp实现跨域请求
查看>>
查看Oracle表中的指定记录在数据文件中的位置
查看>>
ServicePointManager.ServerCertificateValidationCallback 冲突的解决
查看>>
Notes on UNPv1 Ch.5
查看>>
Dubbo实战快速入门 (转)
查看>>
旅游电车
查看>>
Win32中文件的操作
查看>>
【分治】动态点分治 ([ZJOI2007]捉迷藏)
查看>>
「一入 Java 深似海 」系列课程
查看>>
技术胖Flutter第四季-19导航父子页面的跳转返回
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_04-集合_03 斗地主案例(单列)_1_斗地主案例的需求分析...
查看>>
Unity 3D 正交相机(Orthographic)
查看>>
敏捷个人课后练习五主题:改变
查看>>
Lucas&&Exlucas
查看>>
Unity3D ARPG网络游戏编程实践
查看>>
UIAppearance
查看>>
【iCore4 双核心板_ARM】例程十一:DMA实验——存储器到存储器的传输
查看>>
Session History 属性和方法
查看>>
Others
查看>>
20172327 2018-2019-1 《程序设计与数据结构》第五周学习总结
查看>>