P3214 [HNOI2011]卡农

P3214 [HNOI2011]卡农

题意

在集合 {1,2,,n} 中选出 m 个非空子集满足:

  1. 不存在完全相同的两个集合;
  2. 每个元素在所有集合中出现次数之和为偶数。

思路

考虑转移,利用容斥方法进行 Dp。设 fi 表示选了 i 个集合满足条件的方案数:

  1. 首先,如果确定了前 i1 个集合,那么为了满足上面第二个限制这个位置选的集合一定是固定的。前 i1 个集合的选择方案数是 A2n1i1
  2. 上面的方案中有选择了空集的方案。选择空集当且仅当前 i1 个集合已经是合法方案了,即有 fi1 个是多计算的,减去即可。
  3. 还有选择集合相同的方案数。考虑若有相同的集合那么去掉这两个集合剩下的也是合法的,即 fi2。有 i1 个位置和 2n1(i2) 种取法(减去空集和不同的 i2 个集合),所以总共有 fi2(i1)(2n1(i2)) 种,减去即可。

转移式为:

fi=A2n1i1fi1fi2(i1)(2n1(i2))

边界条件为 f0=1,f1=0

实现

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<cmath>
using namespace std;
inline int read(){
	int w=0,x=0;char c=getchar();
	while(!isdigit(c))w|=c=='-',c=getchar();
	while(isdigit(c))x=x*10+(c^48),c=getchar();
	return w?-x:x;
}
namespace star
{
	const int maxn=1e6+10,mod=1e8+7;
	int n,m,pow=1,A[maxn],f[maxn];
	inline int fpow(int a,int b){int ans=1;for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) ans=1ll*ans*a%mod;return ans;}
	inline void work(){
		n=read(),m=read();
		for(int i=1;i<=n;i++) pow=(pow<<1)%mod; pow=(pow-1+mod)%mod;
		A[0]=1;for(int i=1;i<=m;i++) A[i]=1ll*A[i-1]*((pow-i+1+mod)%mod)%mod;
		f[0]=1,f[1]=0;
		for(int i=2;i<=m;i++) f[i]=(A[i-1]-f[i-1]+mod-1ll*f[i-2]*(i-1)%mod*(pow-i+2+mod)%mod+mod)%mod;
		int res=1;
		for(int i=1;i<=m;i++) res=1ll*res*i%mod;
		printf("%lld\n",1ll*f[m]*fpow(res,mod-2)%mod);
	}
}
signed main(){
	star::work();
	return 0;
}

闲话

我搜了下,音阶的意思是从主音到主音的连续音符段,所以一个音阶是若干音符的集合(大概)

所以小余大概是把一个音符分成了一个音阶(

posted @   Star_Cried  阅读(73)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示