[HNOI2011]卡农 题解
题目描述
众所周知卡农是一种复调音乐的写作技法,小余在听卡农音乐时灵感大发,发明了一种新的音乐谱写规则。他将声音分成 n 个音阶,并将音乐分成若干个片段。音乐的每个片段都是由 1 到 n 个音阶构成的和声,即从 n 个音阶中挑选若干个音阶同时演奏出来。为了强调与卡农的不同,他规定任意两个片段所包含的音阶集合都不同。同时为了保持音乐的规律性,他还规定在一段音乐中每个音阶被奏响的次数为偶数。现在的问题是:小余想知道包含 m 个片段的音乐一共有多少种。两段音乐 a 和 b 同种当且仅当将 a 的片段重新排列后可以得到 b。例如:假设 a
为{{1,2},{2,3}},b 为{{3,2},{2,1}},那么 a 与 b 就是同种音乐。由于种数很多,你只需要
输出答案模 100000007(质数)的结果。
输入格式
从文件input.txt中读入数据,输入文件仅一行,具体是用空格隔开的两个正整数n和m,分别表示音阶的数量和音乐中的片段数。20%的数据满足n,m≤5,50%的数据满足n,m≤3000,100%
的数据满足n,m≤1000000。
输出格式
输出文件 output.txt 仅包含一个非负整数,表示音乐的种数模 100000007 的结果。
很强的容斥题。
首先将题意化简一下:从集合$S={1,2,3,...,n}$中选出$m$个子集,满足非空且选出的子集不能相同并保证${1,2,3...n}$每个元素出现次数为偶数。
题目里给出的同种音乐的定义很令人烦躁,所以我们化无序为有序,先使用排列数计算,算出最后结果再除以$m!$(当然直接用组合也可以?)。
然后考虑转移。定义$f[i]$为转移到第$i$个子集,满足所有条件的方案数。如果前$i-1$个子集已经确定,那么根据每个元素出现次数为偶数这条性质,我们就可以确定第$i$个子集(只能选前$i-1$个里出现奇数次的元素)。总的方案数为$A_{2^n-1}^{i-1}$。
这里面包括了许多不满足非空和不相同这两个条件的集合。考虑容斥掉,如果第$i$个子集为空,那么前$i-1$个子集也是一个合法的方案。所以这部分方案数为$f[i-1]$。
还需要去掉存在相同子集的情况。如果第$i$个子集和第$j$个子集重复,那么去掉第$i$个和第$j$个,剩下$i-2$个也是合法方案,数量为$f[i-2]$。此时第$i$个子集有$2^n-1-(i-2)$种方案,和$i$相同的那个子集的位置有$i-1$个,所以这部分的方案数为$f[i-2]\times (i-1)\times (2^n-1-(i-2))$。
$f[i]=A_{2^n-1}^{i-1}-f[i-1]-f[i-2]\times (i-1)\times (2^n-1-(i-2))$
初始化$f[0]=1$。
//实名diss某川 明明当年做题的时候跟我说了题解 还不上去讲
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
#define re register
const int mod=1e8+,N=;
ll f[N],fac,a[N],side,n,m;
ll qpow(ll x,ll y)
{
ll res=;
while(y)
{
if(y&)res=res*x%mod;
x=x*x%mod;
y>>=;
}
return res;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie();
cin>>n>>m;
fac=a[]=f[]=;
for(re int i=;i<=m;i++)fac=fac*i%mod;
fac=qpow(fac,mod-);
side=qpow(,n)-;
for(re int i=;i<=m;i++)a[i]=a[i-]*(side-i+)%mod;
for(re int i=;i<=m;i++)
{
f[i]=a[i-]-f[i-];
f[i]-=(f[i-]*(i-)%mod*(side-i+))%mod;
f[i]=(f[i]%mod+mod)%mod;
}
cout<<f[m]*fac%mod<<endl;
return ;
}
[HNOI2011]卡农 题解的更多相关文章
- 【BZOJ2339】[HNOI2011]卡农 组合数+容斥
[BZOJ2339][HNOI2011]卡农 题解:虽然集合具有无序性,但是为了方便,我们先考虑有序的情况,最后将答案除以m!即可. 考虑DP.如果我们已经知道了前m-1个集合,那么第m个集合已经是确 ...
- [BZOJ2339][HNOI2011]卡农
[BZOJ2339][HNOI2011]卡农 试题描述 输入 见"试题描述" 输出 见"试题描述" 输入示例 见"试题描述" 输出示例 见& ...
- bzoj2339[HNOI2011]卡农 dp+容斥
2339: [HNOI2011]卡农 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 842 Solved: 510[Submit][Status][ ...
- BZOJ2339[HNOI2011]卡农——递推+组合数
题目链接: [HNOI2011]卡农 题目要求从$S=\{1,2,3……n\}$中选出$m$个子集满足以下三个条件: 1.不能选空集 2.不能选相同的两个子集 3.每种元素出现次数必须为偶数次 我们考 ...
- P3214 [HNOI2011]卡农
题目 P3214 [HNOI2011]卡农 在被一题容斥\(dp\)完虐之后,打算做一做集合容斥这类的题了 第一次深感HNOI的毒瘤(题做得太少了!!) 做法 求\([1,n]\)组成的集合中选\(m ...
- [HNOI2011]卡农 (数论计数,DP)
题面 原题面 众所周知卡农是一种复调音乐的写作技法,小余在听卡农音乐时灵感大发,发明了一种新的音乐谱写规则. 他将声音分成 n n n 个音阶,并将音乐分成若干个片段.音乐的每个片段都是由 1 1 1 ...
- [HNOI2011]卡农
题目描述 众所周知卡农是一种复调音乐的写作技法,小余在听卡农音乐时灵感大发,发明了一种新的音乐谱写规则.他将声音分成 n 个音阶,并将音乐分成若干个片段.音乐的每个片段都是由 1 到 n 个音阶构成的 ...
- 【bzoj2339】[HNOI2011]卡农 dp+容斥原理
题目描述 题解 dp+容斥原理 先考虑有序数列的个数,然后除以$m!$即为集合的个数. 设$f[i]$表示选出$i$个集合作为满足条件的有序数列的方案数. 直接求$f[i]$较为困难,考虑容斥,满足条 ...
- bzoj 2339: [HNOI2011]卡农
Description Solution 比较难想.... 我们先考虑去掉无序的这个条件,改为有序,最后除 \(m!\) 即可 设 \(f[i]\) 表示前\(i\)个合法集合的方案数 明确一点: 如 ...
随机推荐
- PHP curl_multi_init函数
curl_multi_init — 返回一个新cURL批处理句柄 说明 resource curl_multi_init ( void ) 允许并行地处理批处理cURL句柄. 参数 此函数没有参数. ...
- 【Flutter学习】基本组件之进度条(LinearProgressIndicator, CircularProgressIndicator)
一,概述 基本有两种类型: 条形进度条(LinearProgressIndicator) new LinearProgressIndicator( backgroundColor: Colors.bl ...
- python学习笔记:模块——自定义模块的3种导入方式
一.定义 模块就是用一堆的代码实现了一些功能的代码的集合,通常一个或者多个函数写在一个.py文件里,而如果有些功能实现起来很复杂,那么就需要创建n个.py文件,这n个.py文件的集合就是模块.如果不懂 ...
- 【react】---react中使用装饰器
一.creact-react-app中使用装饰器 运行 npm run eject 可以让由create-react-app创建的项目的配置项暴露出来 此时,项目中多了一个config文件,并且各个配 ...
- 力扣算法——133.CloneGraph【M】
Given a reference of a node in a connected undirected graph, return a deep copy (clone) of the graph ...
- SQL才是世界上最牛逼的语言!
身处互联网行业,SQL 可能是你需要掌握的核心技能之一. 最早的时候,SQL 作为一门查询数据库的语言,是程序员的必备技能,运维.开发.Web 以及数据等从业人员都需要用到 SQL,毕竟只有查询到正确 ...
- 通往大神之路,百度Java面试题前200页。
基本概念 操作系统中 heap 和 stack 的区别 什么是基于注解的切面实现 什么是 对象/关系 映射集成模块 什么是 Java 的反射机制 什么是 ACID BS与CS的联系与区别 Cookie ...
- 开发效率优化之Git分布式版本控制系统(一)
阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680本篇文章将先从Git分布式版本控制系统来阐述开发效率优化 一,企业 ...
- matlab中struct创建方法
MATLAB中struct创建方法可分为:直接创建法和struct()函数创建法 (1)直接创建: 直接定义字段,像使用一般matlab变量一样,不需要事先声明,支持动态扩充.下面创建一个Studen ...
- spark复习总结03
1.DataFrame的创建方式 1.1 通过加载外部文件创建 //通过sqlContext读取json文件创建DataFrame DataFrame dataFrame=sqlContext.rea ...