推し新世界の卡密

二次元音游人

这是一股照亮混沌的令和时代互联网的一道光,给在电子的海洋里冲浪的阿宅们带来笑容

[HNOI2011] 卡农 题解

超绝最可爱天使酱·2023-06-14 11:13·95 +114514次阅读

[HNOI2011] 卡农 题解

题目传送门

提交记录😭😭😭#

[HNOI2011] 卡农

题目描述#

众所周知卡农是一种复调音乐的写作技法,小余在听卡农音乐时灵感大发,发明了一种新的音乐谱写规则。

他将声音分成 n 个音阶,并将音乐分成若干个片段。音乐的每个片段都是由 1n 个音阶构成的和声,即从 n 个音阶中挑选若干个音阶同时演奏出来。

为了强调与卡农的不同,他规定任意两个片段所包含的音阶集合都不同。同时为了保持音乐的规律性,他还规定在一段音乐中每个音阶被奏响的次数为偶数。

现在的问题是:小余想知道包含 m 个片段的音乐一共有多少种。
两段音乐 ab 同种当且仅当将 a 的片段重新排列后可以得到 b。例如:假设 a{{1,2},{2,3}}b{{2,3},{1,2}},那么 ab 就是同种音乐。

答案对 108+7 取模。

输入格式#

仅一行两个正整数 n,m

输出格式#

输出一行一个整数表示答案。

样例 #1#

样例输入 #1#

Copy
2 3

样例输出 #1#

Copy
1

提示#

【数据范围】
对于 20% 的数据,1n,m5
对于 50% 的数据,1n,m3000
对于 100% 的数据,1n,m106

【样例解释】
音乐为 {{1},{2},{1,2}}

呃呃#

打了半天一直RE20分 发布帖子求助后得到思路www🥵🥵🥵

思路、#

一个集合的非空集合共有2n1

简化题意就是 1234...n元素构成的集合里面取m个子集使之满足

(1)所有选出的m个子集都不能为空

(2)所有选出的m个子集中,能存在两个完全一样的集合。

(3)所有选出的m个子集中,1n每个元素出现的次数必须是偶数

先考虑没有三个限制条件的情况#

2n1个子集里取m个子集共有C2n1m种可能

然后需要减去不符合三个条件的情况:

使用二进制思想考虑#

如果每个元素出现的次数都是偶数,那么它们的异或一定是0

例: 114514xor114514xor1919810xor1919810=0

先考虑第三个条件#

(3).1到n每个元素出现的次数必须是偶数

考虑第i个元素 dp[i]表示取第i个集合出现的方案数

我们发现,如果前m1个集合确定了,那么第m个集合也是确定的

因为对于任意一个元素op,在前m1个集合内如果出现次数是奇数,为了满足条件3,它在第m个集合内一定出现,满足偶数。

如果前m1个集合内如果出现次数是偶数,为了满足条件3,它在第m个集合内一定不出现,满足偶数

所以 加上限制3后,方案数为C2n1i1#

🥰

再考虑第一个条件#

(1).所有选出的m个子集都不能为空

对于dp[i],思考dp[i1]的含义,根据上文定义,可知dp[i1]意思是取第i1个集合出现的方案数,此时它的元素一定有偶数个

最后一个集合为了满足条件3,一定是空集,不合法

对于i,我们可以发现出现空集的方案数就是dp[i1],因为它就等于前i1个集合中出现次数为偶数的方案数


或者前i1个子集的异或为0,则有dp[i1]种方案

🥰

考虑第二个限制条件#

我们需要减去第i个子集和前面某个子集相同的情况

如果我们把相同的两个子集都删去,那么剩下的i2个子集肯定合法,即方案数dp[i2],对于第i个子集,因为删去了两个相同的两个子集,i的方案数为2n1(i2)i2就是前面合法的位置

所以重复的方案数为:dp[i2](2n1(i2))

考虑最后一个问题#

有些 方案 被重复计算了怎么办?


最难思考的地方呜呜呜#

我们随便找一个集合op,假设这是最后一个确定的集合,这个集合有i种选择,所以每种方案重复枚举了i次

对于这个问题,我们只需考虑一个合法的 op 有多少种可能可以用这种方法得到。我们随便在 op 里面选一个集合,它可以成为最后被确定的集合来计算一次 op,而这个集合显然有 |op|=i 种选择,于是我们把答案除以 i 即可。

dp[i]最后要×iの逆元

总结#

dp[i]=(C2n1i1dp[i1](dp[i2](2n1(i2))))i

考虑化简C2n1i1#

其他题都是预处理出阶乘和阶乘的逆元再用函数输出

Copy
for(register int i=1;i<=1e6+5;i++){ x[i]=x[i-1]*i%mod; y[i]=y[i-1]*(qpow(i,mod-2))%mod; // z[i]=qpow(i,mod-2)%mod; }
Copy
inline int C(int n,int m){ if(n<m) return 0; return ((x[n]%mod*y[n-m]%mod)%mod*y[m]%mod)%mod; }

但是我们可以发现 组合数不能这么算的。你代码中的 op 的值域是108+7,远远超出了你预处理的范围 ,这里注意到,op 是固定的,而 i1 比较小,所以可以直接递推

递推

C2n1i1

Cop2=(op)×(op1)2

Cop3=Cop2×(op2)3

Cop4=Cop3×(op3)4

......

Copi=Copi1×(op(i1))i

递推完了!

然后注意一下除法需要用费马小定理处理逆元,因为108+7太大,不能预处理,所以直接在使用的时候用快速幂处理

C的初值为

Copy
int c=((((op-1)*niyuan(2)))%mod*((op)%mod))%mod;

最后附上AC代码#

Copy
#include<bits/stdc++.h> using namespace std; #define int long long namespace Testify{ inline int read(){ int f(1),x(0); char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1; for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+(ch^48); return f*x; } inline void Write(int x){ if(x>9) Write(x/10); putchar(x%10+'0'); } inline void write(int x){ if(x<0) putchar('-'),x=-x; Write(x); putchar('\n'); } } using namespace Testify; const int mod=1e8+7; const int N=1e6+114514; int n,m,dp[N],x[N],y[N]; inline int qpow(int a,int b){ int res=1; while(b){ if(b&1) res=res*a%mod; b>>=1; a=a*a%mod; } return res; } inline int C(int n,int m){ if(n<m) return 0; return ((x[n]%mod*y[n-m]%mod)%mod*y[m]%mod)%mod; } inline int niyuan(int n){ return qpow(n,mod-2)%mod; } signed main(void){ n=read(),m=read(); x[0]=y[0]=1; int op=qpow(2,n)-1; op=((op%mod)+mod)%mod; // cerr<<"op: "<<op<<endl; if(op<m){ write(0); return 0; } // for(register int i=1;i<=op+1;i++){ // x[i]=x[i-1]*i%mod; // y[i]=y[i-1]*(qpow(i,mod-2))%mod; // } // int aa=x[op]; // int c=(x[op]%mod*y[2]%mod*y[op-2]%mod)%mod; // int c=op*(op+mod-1)%mod+qpow(2,mod-2)%mod; int c=((((op-1)*niyuan(2)))%mod*((op)%mod))%mod; // cerr<<"C: "; // clog<<C(op,2)<<endl; dp[1]=0,dp[2]=0; for(register int i=3;i<=m;i++){ dp[i]=((c-dp[i-1]-(dp[i-2]*(op-(i-2))))%mod+mod)%mod*niyuan(i)%mod; // c=(c%mod*y[i]%mod*y[op-i]%mod)%mod; // c=c*(op-i+1+(int)mod)%mod*qpow(i,mod-2)%mod; // c=(c*(op-(i-1))*((qpow(i-1,mod-2)%mod)))%mod; c=((c*(((op-(i-1)))%mod+mod)%mod)%mod*niyuan(i))%mod; // c=c*(op-(i-1)) } write(dp[m]); return 0; }

posted @   超绝最可爱天使酱  阅读(95)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
目录