[JZOJ3424] 【NOIP2013模拟】粉刷匠
题目
题目大意
有\(K\)种颜色的小球,每种颜色的小球有\(c_i\)个。
求相邻颜色不同的排列的方案数。
\(K\leq 15\)且\(c_i\leq 6\)
思考历程&正解1
我是一个智障,所以就先想到了一个智障方法。
首先考虑暴力。
暴力的时候记录上一个的颜色和每种颜色剩余的小球数量,转移的时候选择一种与上一个颜色不同的小球,将它的个数减一。
设状态\(f_{S,i}\)表示状态为\(S\),最后一个小球颜色为\(i\)的方案数。
显然直接这样设状态会爆掉吧……
接着我们发现答案是与小球的顺序无关的,那我们可以考虑将组成一样的压起来。
建立一个桶,桶的下标范围是\([0,6]\),表示小球的个数。桶中的每个元素表示的是小球的个数为下标的颜色个数。
显然,桶的每个元素加起来等于\(15\)(如果一开始\(K<15\),就补\(0\))
可以计算这个桶的方案数:
相当于将\(15\)个球放进\(7\)个箱子里,每个箱子可以为空:\(C_{15+7-1}^{7-1}=54264\)
可以存下。
这个桶可以用个\(7\)位的\(16\)进制数来存,不会超过int
。用\(map\)给每个桶分配一个下标。
然后\(i\)的定义也要变一下,表示最后一个小球的颜色的个数。范围在\([0,6]\),显然不会炸。
由于多组数据,所以考虑反着转移。\(f_{S,i}\)中的\(S\)表示的状态是已经放了的状态(不是剩余的状态)。
转移的时候枚举\(j\)。设桶下标为\(j\)的数是\(k\),如果\(i=j\),由于不能重复,所以乘上\(k-1\)。否则直接乘\(k\)。
这些是预处理的部分。对于每个询问,由于它按照一定顺序排列,所以要除以排列数。排列数有个公式:\(\frac{(\sum{c_i})!}{\prod {c_i!}}\)(不会证明……)
正解2
DYP的高级解法。
设\(f_{i,j}\)表示做到第\(i\)个颜色,相邻相等的个数为\(j\)。
按照颜色一层一层转移,每次转移的时候插空。
现在由\(f_{i,j}\)往后面的转移,设\(sum=\sum_{1\leq k\leq i}{c_k}\)
枚举插空的位置个数\(x\)和插在相邻相等位置之间的个数\(y\)。
转移:\(f_{i,j}*C_{sum+1-j}^{x-y}*C_j^y\to f_{i+1,j-y+c_{i+1}-x}\)
感觉我的方法简单多了
代码(正解1)
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <cassert>
#define mo 1000000007
inline int my_pow(int x,int y){
int res=1;
for (;y;y>>=1,x=1ll*x*x%mo)
if (y&1)
res=1ll*res*x%mo;
return res;
}
int pow16[8],fac[16];
int cnt;
map<int,int> h;
int f[200000][7];
int q[200000];
inline void init(){
h[15]=++cnt;
f[cnt][6]=1;
int head=0,tail=1;
q[1]=15;
do{
int x=q[++head],s=h[x];
for (int j=0;j<6;++j){
int k=x/pow16[j]%16;
if (k){
int y=x-pow16[j]+pow16[j+1];
int *p=&h[y];
if (*p==0){
*p=++cnt;
q[++tail]=y;
}
for (int i=1;i<=6;++i)
(f[*p][j+1]+=1ll*f[s][i]*(i!=j?k:k-1)%mo)%=mo;
}
}
}
while (head!=tail);
}
int main(){
pow16[0]=1;
for (int i=1;i<=7;++i)
pow16[i]=pow16[i-1]*16;
fac[0]=1;
for (int i=1;i<=15;++i)
fac[i]=1ll*fac[i-1]*i%mo;
init();
int T;
scanf("%d",&T);
while (T--){
int K;
scanf("%d",&K);
int x=15-K;
for (int i=1;i<=K;++i){
int c;
scanf("%d",&c);
x+=pow16[c];
}
int s=h[x];
long long ans=0;
for (int i=1;i<=6;++i)
ans+=f[s][i];
ans%=mo;
for (int i=0;i<=6;++i)
ans=1ll*ans*fac[x/pow16[i]%16]%mo;
ans=1ll*ans*my_pow(fac[15],mo-2)%mo;
printf("%lld\n",ans);
}
return 0;
}
总结
排列组合一类的DP,可以试着一层层插空。
[JZOJ3424] 【NOIP2013模拟】粉刷匠的更多相关文章
- 2014.7.8模拟赛【笨笨当粉刷匠】|bzoj1296 [SCOI]粉刷匠
笨笨太好玩了,农田荒芜了,彩奖用光了,笨笨只好到处找工作,笨笨找到了一份粉刷匠的工作.笨笨有n条木板需要被粉刷.每条木板被分成m个格子,每个格子要被刷成红色或蓝色.笨笨每次粉刷,只能选择一条木板上一段 ...
- 【JZOJ3424】粉刷匠
description 赫克托是一个魁梧的粉刷匠,而且非常喜欢思考= = 现在,神庙里有N根排列成一直线的石柱,从1到N标号,长老要求用油漆将这些石柱重新粉刷一遍.赫克托有K桶颜色各不相同的油漆,第i ...
- BZOJ 1296: [SCOI2009]粉刷匠 分组DP
1296: [SCOI2009]粉刷匠 Description windy有 N 条木板需要被粉刷. 每条木板被分为 M 个格子. 每个格子要被刷成红色或蓝色. windy每次粉刷,只能选择一条木板上 ...
- cojs 疯狂的粉刷匠 疯狂的斐波那契 题解报告
疯狂的斐波那契 学习了一些奇怪的东西之后出的题目 最外层要模p是显然的,然而内层并不能模p 那么模什么呢,显然是模斐波那契的循环节 那么我们可以一层层的求出每层的斐波那契循环节 之后在从内向外用矩阵乘 ...
- BZOJ 1296: [SCOI2009]粉刷匠( dp )
dp[ i ][ j ] = max( dp[ i - 1 ][ k ] + w[ i ][ j - k ] ) ( 0 <= k <= j ) 表示前 i 行用了 j 次粉刷的机会能正 ...
- 【NOIP2013模拟】终极武器(经典分析+二分区间)
No.2. [NOIP2013模拟]终极武器 题意: 给定你一些区间,然后让你找出\(1\sim 9\)中的等价类数字. 也就是说在任何一个区间里的任何一个数,把其中后\(k\)位中的某一位换成等价类 ...
- 【BZOJ1296】[SCOI2009]粉刷匠(动态规划)
[BZOJ1296][SCOI2009]粉刷匠(动态规划) 题面 BZOJ 洛谷 题解 一眼题吧. 对于每个串做一次\(dp\),求出这个串刷若干次次能够达到的最大值,然后背包合并所有的结果即可. # ...
- bzoj1296【SCOI2009】粉刷匠
1296: [SCOI2009]粉刷匠 Time Limit: 10 Sec Memory Limit: 162 MB Submit: 1479 Solved: 837 [id=1296" ...
- 1296: [SCOI2009]粉刷匠[多重dp]
1296: [SCOI2009]粉刷匠 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1919 Solved: 1099[Submit][Statu ...
- 【BZOJ1296】[SCOI2009]粉刷匠 (DP+背包)
[SCOI2009]粉刷匠 题目描述 \(windy\)有 \(N\) 条木板需要被粉刷. 每条木板被分为 \(M\) 个格子. 每个格子要被刷成红色或蓝色. \(windy\)每次粉刷,只能选择一条 ...
随机推荐
- 最长递增子序列nlogn的做法
费了好大劲写完的 用线段树维护的 nlogn的做法再看了一下 大神们写的 nlogn 额差的好远我写的又多又慢 大神们写的又少又快时间 空间 代码量 哪个都赶不上大佬们的代码 //这是我写的 ...
- GP下CalculateField的用法
以前用过这个类做字段计算,许久不用有些忘却,记录一下使用方式 public static void CalculateField(IFeatureLayer featureLayer,IField f ...
- rest_framework 认证组件 权限组件
认证组件 权限组件 一.准备内容 # models class User(models.Model): name = models.CharField(max_length=32) pwd = mod ...
- 前端 css 补充内容
给个菜鸟教程的css教程网址(全的狠!!!): https://www.runoob.com/css/css-tutorial.html 下面是几张css基础样式图:
- PHP算法之最长公共前缀
### 解题思路 方法太笨重后期优化 循环比较 循环长度利用max(最长字符串的循环) 不满住条件的截取 ### 代码 ```php class Solution { /** * @ ...
- hadoop的基准测试
hadoop的基准测试 实际生产环境当中,hadoop的环境搭建完成之后,第一件事情就是进行压力测试,测试我们的集群的读取和写入速度,测试我们的网络带宽是否足够等一些基准测试 测试写入速度 向HDFS ...
- NX二次开发-UFUN计算两点距离UF_VEC3_distance
NX11+VS2013 #include <uf.h> #include <uf_curve.h> #include <uf_vec.h> UF_initializ ...
- CentOS 启动提示unexpected inconsistency;RUN fsck MANUALLY, ntfs的input/output Error,InPageError c000009c使用chkdsk修复磁盘,12款Linux系统恢复工具
CentOS这两天服务器出了问题了,提示如下: unexpected inconsistency;RUN fsck MANUALLY An error occurred during the file ...
- 微信-小程序-开发文档-服务端-模板消息:templateMessage.send
ylbtech-微信-小程序-开发文档-服务端-模板消息:templateMessage.send 1.返回顶部 1. templateMessage.send 本接口应在服务器端调用,详细说明参见服 ...
- oracle11g 导出表报EXP-00011:table不存在。
oracle11g 导出表报EXP-00011:table不存在. oracle11g,在用exp命令备份数据库时,如果表中没有数据报EXP-00011错误,对应的表不存在.这导致对应的空表无法备份. ...