[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\)每次粉刷,只能选择一条 ...
随机推荐
- selenium 滑动页面至元素可见
滚动页面 在自动化操作中,如果web页面过长,而我们需要的元素并不在当前可视页面中,那么selenium就无法对其进行操作:此时,我们就需要像平时操作浏览器一样来滚动页面,使我们需要操作的对象可见! ...
- Linux编程获取本机IP地址
使用函数getifaddrs来枚举网卡IP,当中使用到的结构体例如以下所看到的: struct ifaddrs { struct ifaddrs *ifa_next; /* Next item in ...
- zic - 时区编辑器
总览 zic [ -v ] [ -d directory ] [ -l localtime ] [ -p posixrules ] [ -L leapsecondfilename ] [ -s ] [ ...
- boost asio tcp 多线程
common/pools.h // common/pools.h #pragma once #include <string> #include <boost/pool/pool.h ...
- 10.Struts2值栈
1.什么是值栈 * 值栈就相当于Struts2框架的数据的中转站,向值栈存入一些数据.从值栈中获取到数据. * ValueStack 是 struts2 提供一个接口,实现类 OgnlValueSta ...
- 关于h5打包后 wag包无法安装的问题
如果不是逻辑错误,那么有可能是下列三种情况之一, 1 wgt打包时的appid与安装包不符 2 打包wgt文件和打包安装包文件 用的不是同一个HBuilder账户 3 安装包打包时权限配置,和wgt包 ...
- python编写微信公众号首图思路详解
前言 之前一直在美图秀秀调整自己的微信公众号首图,效果也不尽如人意,老是调来调去,最后发出来的图片被裁剪了一大部分,丢失部分关键信息,十分恼火,于是想着用python写一个程序,把微信公众号首图的模式 ...
- sed 一 文本处理工具
简介 sed 采用的是流编辑模式: 最明显的特点是,在 sed 处理数据之前,需要预先提供一组规则,sed 会按照此规则来编辑数据. sed 会根据脚本命令来处理文本文件中的数据,这些命令要么从命令行 ...
- JAVA SE Download
{ //https://www.oracle.com/technetwork/java/javase/downloads/index.html }
- Ruby 安装 – Windows
Ruby 安装 – Windows 下面列出了在 Windows 机器上安装 Ruby 的步骤. 注意:在安装时,您可能有不同的可用版本. - Window 系统下,我们可以使用 RubyInstal ...