BZOJ1079 [SCOI2008]着色方案[组合计数DP]
$有a_{1}个1,a_{2}个2,...,a_{n}个n(n<=15,a_{n}<=5),求排成一列相邻位不相同的方案数。$
关于这题的教训记录:
- 学会对于复杂的影响分开计,善于发现整体变化,用整体法(没错就是和物理那种差不多)。
- 推dp方程时怕边界问题不好处理时可以采用向前推的方法,就如$f[x]=f[i]+...$,可以(部分)避免越界。
我好菜啊。。除了个dp状态设计对了其他什么都没写上来qwq。基于每次插入时数字的数量都不固定,所以我可以设法将其固定下来。按顺序依次插入1,2,3,...,n即可。因为我是要统计相同不相邻方案,转移的时候肯定是插空啊,所以再设计一维表示有多少个相邻相同的($f[i][j]$),这样就好做了。然而我在这里卡主了。。因为我看数据每个数字最多5个嘛,分类大力讨论一下的事情。然而讨论到3的时候我已经崩溃掉了。觉得写法有问题,但是又不知道怎么简化。
磕了几小时没出来QwQ,翻了题解%%%,发现还是思路狭窄了啊。每个数k个,因为要往空挡里面插,不算几张合在一起的话,分开的情况是很容易想的。而我有连续数字插入的时候,可以枚举其分组。分k组的时候,这些牌单独来看是会产生出新的$n-k$个连续位的。再看我插入时,把连续数字当做整体(就是看成一个数字),插入之前的连续位空挡相当于把他填起来了,否则无影响。所以枚举插到数字$i$,枚举之前有$j$空位连续数字,当下分为$k$组,插到之前$j$个空位里的有$l$个,之前方案$f[i][j]$,$j$个空位中选出来$l$个是$C_{j}^{l}$,剩下的非连续数字的空位还要再选$C_{sum[i-1]+1-j}^{k-l}$个,这些空位里去填$k$组,问题转为一排数字划为k组的不同方案,是经典隔板问题,有$C_{a[i]-1}^{k-1}$种。所以dp方程就出来啦。见code。可以感性认识这是不重不漏的。(??!)
可能我组合计数还是太差了啊。几星期后到数学专题去好好补一发算了。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define dbg(x) cerr<<#x<<" = "<<x<<endl
#define dddbg(x,y,z) cerr<<#x<<" = "<<x<<" "<<#y<<" = "<<y<<" "<<#z<<" = "<<z<<endl
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
template<typename T>inline char MIN(T&A,T B){return A>B?A=B,:;}
template<typename T>inline char MAX(T&A,T B){return A<B?A=B,:;}
template<typename T>inline T _min(T A,T B){return A<B?A:B;}
template<typename T>inline T _max(T A,T B){return A>B?A:B;}
template<typename T>inline T read(T&x){
x=;int f=;char c;while(!isdigit(c=getchar()))if(c=='-')f=;
while(isdigit(c))x=x*+(c&),c=getchar();return f?x=-x:x;
}
const ll P=1e9+;
int f[][],fac[],C[][];
int T,n,s[],sum[];
inline void inc(int&A,int B){A+=B;A>=P?A-=P:;}
inline void preprocess(){
C[][]=;
for(register int i=;i<=;++i){C[i][]=;for(register int j=;j<=;++j)C[i][j]=(0ll+C[i-][j]+C[i-][j-])%P;}
} int main(){//freopen("test.in","r",stdin);freopen("test.out","w",stdout);
preprocess();read(n);
for(register int i=;i<=n;++i)read(s[i]);
f[][s[]-]=;
for(register int i=;i<=n;++i)sum[i]=s[i]+sum[i-];
for(register int i=;i<=n;++i)
for(register int j=;j<=sum[i-]-i+;++j)
for(register int k=;k<=s[i];++k)
for(register int l=;l<=_min(j,k);++l)
inc(f[i][j+s[i]-k-l],f[i-][j]*1ll*C[j][l]%P*C[sum[i-]+-j][k-l]%P*C[s[i]-][k-]%P);
printf("%d\n",f[n][]);
return ;
}
hihocoder扑克牌:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define dbg(x) cerr<<#x<<" = "<<x<<endl
#define dddbg(x,y,z) cerr<<#x<<" = "<<x<<" "<<#y<<" = "<<y<<" "<<#z<<" = "<<z<<endl
using namespace std;
typedef unsigned long long ull;
typedef pair<int,int> pii;
template<typename T>inline char MIN(T&A,T B){return A>B?A=B,:;}
template<typename T>inline char MAX(T&A,T B){return A<B?A=B,:;}
template<typename T>inline T _min(T A,T B){return A<B?A:B;}
template<typename T>inline T _max(T A,T B){return A>B?A:B;}
template<typename T>inline T read(T&x){
x=;int f=;char c;while(!isdigit(c=getchar()))if(c=='-')f=;
while(isdigit(c))x=x*+(c&),c=getchar();return f?x=-x:x;
}
const int N=;
ull f[N][],fac[],C[][];
int T,n,cnt[N],s[N],sum[N];
char ch[]; int main(){//freopen("test.in","r",stdin);freopen("test.out","w",stdout);
read(T);fac[]=,fac[]=,fac[]=,fac[]=;C[][]=;
for(register int i=;i<=;++i){
C[i][]=;
for(register int j=;j<=;++j)C[i][j]=C[i-][j]+C[i-][j-];
}
for(register int o=;o<=T;++o){
read(n);memset(cnt,,sizeof cnt);
for(register int i=;i<=n;++i){
scanf("%s",ch+);int x=ch[]&;
if(ch[]=='A')x=;else if(ch[]=='T')x=;else if(ch[]=='J')x=;else if(ch[]=='Q')x=;else if(ch[]=='K')x=;
++cnt[x];
}n=;
for(register int i=;i<=;++i)if(cnt[i])s[++n]=cnt[i],sum[n]=s[n]+sum[n-];
memset(f,,sizeof f);f[][s[]-]=;
for(register int i=;i<=n;++i)
for(register int j=;j<=sum[i-]-i+;++j)
for(register int k=;k<=s[i];++k)
for(register int l=;l<=_min(j,k);++l)
f[i][j+s[i]-k-l]+=f[i-][j]*C[j][l]*C[sum[i-]+-j][k-l]*C[s[i]-][k-];
for(register int i=;i<=n;++i)f[n][]*=fac[s[i]];
printf("Case #%d: %llu\n",o,f[n][]);
}
return ;
}
BZOJ1079 [SCOI2008]着色方案[组合计数DP]的更多相关文章
- BZOJ1079:[SCOI2008]着色方案(DP)
Description 有n个木块排成一行,从左到右依次编号为1~n.你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块. 所有油漆刚好足够涂满所有木块,即c1+c2+...+ck=n.相邻两个 ...
- BZOJ1079 [SCOI2008]着色方案 【dp记忆化搜索】
题目 有n个木块排成一行,从左到右依次编号为1~n.你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块. 所有油漆刚好足够涂满所有木块,即c1+c2+-+ck=n.相邻两个木块涂相同色显得很难看 ...
- [luogu2476][bzoj1079][SCOI2008]着色方案【动态规划】
题目描述 有n个木块排成一行,从左到右依次编号为1~n.你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块.所有油漆刚好足够涂满所有木块,即c1+c2+-+ck=n.相邻两个木块涂相同色显得很难 ...
- BZOJ1079 [SCOI2008]着色方案 动态规划
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1079 题目概括 有n个木块排成一行,从左到右依次编号为1~n.你有k种颜色的油漆,其中第i种颜色的 ...
- BZOJ1079: [SCOI2008]着色方案 (记忆化搜索)
题意:有n个木块排成一行,从左到右依次编号为1~n.你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块. 所有油漆刚好足够涂满所有木块,即c1+c2+...+ck=n.相邻两个木块涂相同色显得很 ...
- 2018.10.20 bzoj1079: [SCOI2008]着色方案(多维dp)
传送门 dp妙题. f[a][b][c][d][e][last]f[a][b][c][d][e][last]f[a][b][c][d][e][last]表示还剩下aaa个可以用一次的,还剩下bbb个可 ...
- bzoj1079: [SCOI2008]着色方案
dp.以上次染色时用的颜色的数量和每种数量所含有的颜色作状态. #include<cstdio> #include<algorithm> #include<cstring ...
- 【记忆化搜索】bzoj1079 [SCOI2008]着色方案
#include<cstring> #include<cstdio> using namespace std; #define MOD 1000000007 typedef l ...
- bzoj1079: [SCOI2008]着色方案
ci<=5直接想到的就是5维dp了...dp方程YY起来很好玩...写成记忆化搜索比较容易 #include<cstdio> #include<cstring> #inc ...
随机推荐
- easyui datagrid checkbox复选框取消单击选中事件、初始全选全不选等问题解决
系统业务需要,导入的列表数据默认全部选中,且不可取消选中行.全部店铺优惠券发放过后导入的数据全部清空.如图所示: 一.初始化页面默认全部选中“selectAll”,全部不选中“unselectAll” ...
- iscsi脚本
服务端 #!/bin/bash #测试主机是否可以联网 echo -e "\033[31m即将测试主机是否可以联网\033[0m" ping -c 4 www.baidu.com ...
- 【VS开发】OutputWnd自动滚动
最近在尝试VS2010中的各种新鲜插件,首先从最简单的输出窗口入手. VS2010向导中产生的输出窗口是通过CMainFrame中的COutputWnd类的对象m_wndOutput生成的.为了向输出 ...
- Fragment通过接口回调向父Activity传值
Fragment: 定义一个接口,在onAttach()方法中,实例化接口对象.要求是父Activity要实现该接口.然后在你想发送信息的地方调用callBackValue.sendMessageVa ...
- ASP.NET Core EFCore 之Code First
1.在.NET Core项目中使用Nuget引用包 Sql Server 请安装 Microsoft.EntityFrameworkCore.SqlServer 2.添加实体类 [Table(&quo ...
- Interval List Intersections
Given two lists of closed intervals, each list of intervals is pairwise disjoint and in sorted order ...
- c++ 【递归算法】梵塔问题
一道递归水题,2话不说,直接放代码: #include<iostream> using namespace std; int k; void move(int m,char a,char ...
- centos终端显示字母重叠
在使用VMware虚拟机安装linux之后,之后调整了中文显示,但是后来不知道怎么回事在终端显示的字母很多都是重叠的. 在百度上也找到很多的解决办法 eg: 终端键入:vi /etc/fonts/co ...
- 怎么快速写好看的手机menu菜单
要达到这样的效果: <div class="menu"> <div class="menu-1"> <img alt=" ...
- javaagent项目中使用
相关代码参考:http://blog.csdn.net/catoop/article/details/51034778 近期项目中需要对SpringMVC中的Controller方法进行拦截做预处理, ...