[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\)每次粉刷,只能选择一条 ...
随机推荐
- opencv——常见的操作
一 图像阈值处理 准备一张灰度图像 阈值处理通常是设定一个阈值,让图片的所有像素点的值与其比较做出一系列的操作. 在opencv常用的阈值处理函数有五种,分别是THRESH_BINARY.THRESH ...
- js 实用封装 点击按钮复制到剪贴板
封装剪贴板: function Copy(str) { var save = function (e) { //设置需要复制模板的内容 e.clipboardData.setData('text/pl ...
- SpringMVC前后端参数交互
Controller中使用JSON方式有多种 关键在于ajax请求是将数据以什么形式传递到后台 HTTP请求中: 如果是get请求,那么表单参数以name=value&name1=value1 ...
- 前端自动化构建工具——gulp环境搭建教程
gulp是前端工程化的工具,它可以对html,css,js等代码和图片进行压缩,也可以对sass和less等预处理语言进行编译,代码部署.gulp学起来简单,用起来方便,大大提高我们工作效率. 这里可 ...
- 使用lombok时@Setter @Getter无效
原文链接 : https://blog.csdn.net/marion158/article/details/87893480 lombok是一个帮助简化代码的工具,通过注解的形式例如@Setter ...
- ubuntu查看时间同步服务器的匹配源
当服务器时间与设定好的同步时间源的时间有差异的时候,一般都需要先查看本机的时间同步服务功能是否在正常的运转,以及同步的时间源是哪里,在这里为大家提供一个检查时间用的命令. ubuntu版本 servi ...
- leetcode-52-N皇后②
题目描述: 方法一:回溯 class Solution: def totalNQueens(self, n: int) -> int: def backtrack(i,tmp,col,z_dia ...
- leetcood学习笔记-88-合并两个有序数组
题目描述: 第一次提交: class Solution: def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -&g ...
- scala中Trait简单使用
trait Log { def log(message:String) = println("log:" + message) } /** * 为实例混入trait * */ tr ...
- thinkphp cookie支持
系统内置了一个cookie函数用于支持和简化Cookie的相关操作,该函数可以完成Cookie的设置.获取.删除操作. Cookie设置 cookie('name','value'); //设置coo ...