ssoj1306卡农(canon)(组合数学+乘法逆元)
来源:互联网 发布:ue ui设计美工招聘 编辑:程序博客网 时间:2024/04/29 18:41
题目描述
众所周知卡农是一种复调音乐的写作技法,小余在听卡农音乐时灵感大发,发明了一种新的音乐谱写规则。他将声音分成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的结果。
样例输入
样例输出
提示
样例解释:音乐为{{1},{2},{1,2}}
<span style="font-size:18px;">#include <iostream>#include <cstring>#include <cstdlib>#include <cstdio>#include <algorithm>#include <cmath>#define ll long long using namespace std;const int maxn=1000006;const int mod=100000007;int n,m;ll f[maxn],g[maxn],Pow,d,x,y;inline int get(){ char c;while(!isdigit(c=getchar())); int v=c-48;while(isdigit(c=getchar()))v=v*10+c-48; return v;}inline ll exgcd(ll a,ll b,ll &x,ll &y){ if(b==0){ x=1;y=0;return a;}else{ ll tmp=exgcd(b,a%b,x,y); ll t=x; x=y; y=t-(a/b)*y; return tmp;}}inline ll power(int a,int b){ ll ret=1,tmp=a; while(b){ if(b&1)ret=ret*tmp%mod; tmp=tmp*tmp%mod; b>>=1;}return ret;}int main(){ n=get();m=get(); Pow=power(2,n)%mod; g[0]=1;f[0]=f[1]=f[2]=0; for(int i=1;i<=m;++i)g[i]=g[i-1]*(Pow-i)%mod; ll i; for(i=3;i<=m;++i){ f[i]=g[i-1]-f[i-1]-(i-1)*(Pow+1-i)%mod*f[i-2]%mod; f[i]%=mod;}if(f[m]<0)f[m]+=mod;d=1;for(int i=1;i<=m;++i)d=d*i%mod;exgcd(d,mod,x,y);d=(x%mod+mod)%mod;f[m]=d*f[m]%mod;printf("%lld\n",f[m]);return 0;}</span>
思路:由数学知识可知总共有2^n-1个集合,f[ i ]为取i个集合的合法方案,g[ i ]为取i个集合的总方案(包括不合法的),因为音阶要取偶数个,所以第m个方案可由前m-1的方案决定。即f[ i ]为g[ i-1 ]-♂(某个数)。原来是无序,现在我们假设它有序,最后再用乘法逆元求(f[ m ]/m!)mod MOD。
这♂是什么呢
“不合法的那些方案,不合法的方案有两种:
1、前i−1段的方案是合法的,这时前i−1段,每种音调的个数是偶数个,而加入第i段后,由于第i段中每种不同的音调都只能出现1次,那么加入第i段后每种音调的个数可能出现奇数个,就不合法了,这种情况的方案数有f[i−1]种
2、第i段和前i−1段中某一段是相同的,为了便于叙述,我们说前i−1段中与第i段相同的段是第i段的冲突对象,那么冲突对象可以在1到i−1号段中选一个,有(i−1)种选法,选好冲突对象后,剩下的i−2个不冲突的段的方案数是f[i−2](有2个子集被去掉了,某些种音调里去掉了偶数次,现在每种音调的出现次数就是偶数次,那么剩下的段肯定是合法的),第i段和其冲突对象对应的子集有(2n−1)−(i−2),解释:n个音调的子集总数共有(2n−1)种,然后前i−1段中有i−2个不和第i段相同的段已经确定下来了,占用了其中的i−2个子集,因此前面的式子是(2n−1)−(i−2),因此乘法计数可以得到二号情况的方案数是f[i−2](i−1)[(2n−1)−(i−2)]
那么就能得到初步的一个递推式:
f[i]=Ai−12n−1−f[i−1]−f[i−2](i−1)[(2n−1)−(i−2)]
然后用g[i]代进去替换掉那个A
f[i]=g[i−1]−f[i−1]−f[i−2](i−1)[(2n−1)−(i−2)]”
- ssoj1306卡农(canon)(组合数学+乘法逆元)
- Lucas定理+乘法逆元+组合数学(hdu5226)
- hdu - 4869 - Turn the pokers(组合数学 + 乘法逆元)
- HDU 5894 hannnnah_j’s Biological Test (组合数学 + 快速幂 + 乘法逆元)
- hdu5651(乘法逆元&&组合数)
- bzoj1004(组合+乘法逆元)(简便)
- 数学(乘法逆元)hdu5225
- BZOJ 2339 HNOI2011 卡农 组合数学
- [BZOJ 2339][HNOI 2011]卡农(组合数学)
- 【bzoj2339】【HNOI2011】【卡农】【组合数学+dp】
- Codeforces Round #295 (Div. 1) C. Pluses everywhere (组合数学+乘法逆元)
- [HDU 5184][BestCoder #32]Brackets(卡特兰数+组合数学+乘法逆元)
- 组合数、逆元,数学
- ssoj2431 棋盘路径(乘法逆元+组合数)
- Codeforces 521C 组合数取模(乘法逆元)
- lightoj 1067 - Combinations (组合数、乘法逆元)
- HDU5894分位置(组合数,lucas,乘法逆元)
- 51nod:1256 乘法逆元(数学)
- HDU 5412 CRB and Queries 求区间第k小 CDQ分治+整体二分
- 1051. Pop Sequence (25)
- 几个不错的基于jquery的js图片轮播插件
- 理解Fragment生命周期
- iOS苹果推送通知服务
- ssoj1306卡农(canon)(组合数学+乘法逆元)
- Python中的全局变量与局部变量
- JFinal学习笔记(四) 实现简单的图片上传
- 修改mysql主键的值为自增
- android studio开发Activity切换动画以及ButterKnife注解简单应用
- MVC之多个信函打印
- 修改:类shell程序的简化实现,尝试消除ctrl+c,结果处理完信号后挑出了while循环
- 实现主成分分析和白化
- UITabBarItem改变字体颜色