[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 的结果。【输入输出样例】

输入输出样例

输入样例#1:
2 3
输出样例#1:
1

说明

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

首先题目里说是无序的,但是不要管它,我们先把它看成有序的,最后除以一个m!即可。我们考虑补集转换,首先所有的子集个数应该是2^n1,我们定义f[i]为挑选i个片段的合法的方案数,此时总数应该是A(2^n1,i1)(排列数)。为什么是i1而不是i呢?因为要保证总数是偶数,也就是说如果你确定了i1个片段第i个片段也就确定了。而这样肯定多算了,具体来说有两部分: 
1、如果前i1个已经合法,那么第i个就是空集,这样肯定不合法,所以要减去f[i1]。 
2、如果根据前i1个确定出来的第i个集合和前面的某一个重复,这样肯定是不合法的。 
因为考虑顺序,所以那个和第i个重复的集合有i1种位置,对于每种位置,

当前的总数偶数去掉两个数之后还是偶数,所以剩下其他数的方案数为f[i2]

然后我们需要算出有多少种可能重复的方案,因为我们已经确定了(i2)个位置,所以方案数为(2^n1(i2))

所以总体的方程就是:f[i]=A(2^n1,i1)f[i1]f[i2](2^n1(i2))(i1) 
最后在乘上一个m!关于mod的逆元即可。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 long long Mod=100000007,s;
 7 long long n,m;
 8 long long pre[1000001],A[1000001],f[1000001];
 9 long long qpow(long long x,int y)
10 {
11     long long res=1;
12     while (y)
13     {
14         if (y%2==1)
15         {
16             res=(res*x)%Mod;
17         }
18       x=(x*x)%Mod;
19       y/=2;
20     }
21     return res;
22 }
23 int main()
24 {long long i;
25     cin>>n>>m;
26      s=(qpow(2,n)-1+Mod)%Mod;
27       //p=qpow(2,n)%Mod;
28      pre[0]=1;
29      for (i=1;i<=m;i++)
30      {
31             pre[i]=(pre[i-1]*(s-i+1+Mod)%Mod)%Mod;
32      }
33      A[1]=1;
34      for (i=2;i<=m;i++)
35      A[i]=((Mod-Mod/i)*A[Mod%i]+Mod)%Mod;
36       f[1]=0;f[2]=0;
37     for (i=3;i<=m;i++)
38     {
39         f[i]=(pre[i-1]+Mod)%Mod;
40         f[i]=(f[i]-f[i-1]+Mod)%Mod;
41         if (f[i]<0) f[i]+=Mod;
42         f[i]=(f[i]-((f[i-2]*(i-1)%Mod)*((s-i+2+Mod)%Mod))%Mod+Mod)%Mod;
43         if (f[i]<0) f[i]+=Mod;
44     }
45     for (i=1;i<=m;i++)
46     f[m]=(f[m]*A[i])%Mod;
47 cout<<f[m];
48 }

 

转载于:https://www.cnblogs.com/Y-E-T-I/p/7192063.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用\[1\]和引用\[2\]的描述,题目中的影魔拥有n个灵魂,每个灵魂有一个战斗力ki。对于任意一对灵魂对i,j (i<j),如果不存在ks (i<s<j)大于ki或者kj,则会为影魔提供p1的攻击力。另一种情况是,如果存在一个位置k,满足ki<c<kj或者kj<c<ki,则会为影魔提供p2的攻击力。其他情况下的灵魂对不会为影魔提供攻击力。 根据引用\[3\]的描述,我们可以从左到右进行枚举。对于情况1,当扫到r\[i\]时,更新l\[i\]的贡献。对于情况2.1,当扫到l\[i\]时,更新区间\[i+1,r\[i\]-1\]的贡献。对于情况2.2,当扫到r\[i\]时,更新区间\[l\[i\]+1,i-1\]的贡献。 因此,对于给定的区间\[l,r\],我们可以根据上述方法计算出区间内所有下标二元组i,j (l<=i<j<=r)的贡献之和。 #### 引用[.reference_title] - *1* *3* [P3722 [AH2017/HNOI2017]影魔(树状数组)](https://blog.csdn.net/li_wen_zhuo/article/details/115446022)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [洛谷3722 AH2017/HNOI2017 影魔 线段树 单调栈](https://blog.csdn.net/forever_shi/article/details/119649910)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值