#容斥,组合计数#洛谷 3214 卡农

本文详细介绍了洛谷3214卡农问题,涉及从集合S=[1~n]中选择m个子集,满足特定条件的计数方法。分析中提到,题目实际考察的是容斥原理的应用,并给出了动态规划的解题思路,包括状态转移方程。最后,提供了实现这一算法的代码片段。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

在集合S=[1∼n]S=[1\sim n]S=[1n]中选出mmm个子集,满足三点性质:

  1. 所有选出的mmm个子集都不能为空。
  2. 所有选出的mmm个子集中,不能存在两个完全一样的集合。
  3. 所有选出的mmm个子集中,1到nnn每个元素出现的次数必须是偶数。

问有多少种不同的方法,两个子集 a 和 b 同种当且仅当将 a 的子集重新排列后可以得到 b


分析

首先作为一道黑题,它还是具有它的难度的,因为是真的恶心。
首先不同就是个幌子,只要答案除以m!m!m!的阶乘就可以了。
dp[i]dp[i]dp[i]表示前iii个合法集合的方法数
第二,考虑容斥,若是偶数,那么第iii个是唯一的,也就是前i−1i-1i1个出现奇数次的,所以总共方案是P2n−1i−1P^{i-1}_{2^n-1}P2n1i1
然后,非空,那么当第iii个集合为空时,那么方案数是dp[i−1]dp[i-1]dp[i1]
接着不能存在完全一样的集合,若jjjiii重复,那么剩下的i−2i-2i2个子集是合法方案,jjji−1i-1i1种取值,第jjj个子集可以有2n−1−(i−2)2^n-1-(i-2)2n1(i2)种方案,所以也就是dp[i−2]×(i−1)×(2n−i+1)dp[i-2]\times (i-1)\times (2^n-i+1)dp[i2]×(i1)×(2ni+1)
综上所述,dp[i]=P2n−1i−1−dp[i−1]−dp[i−2]×(i−1)×(2n−i+1)dp[i]=P^{i-1}_{2^n-1}-dp[i-1]-dp[i-2]\times (i-1)\times (2^n-i+1)dp[i]=P2n1i1dp[i1]dp[i2]×(i1)×(2ni+1)
dp[0]=1,dp[1]=0dp[0]=1,dp[1]=0dp[0]=1,dp[1]=0(是真的骚)


代码

#include <cstdio>
#define rr register
using namespace std;
typedef long long ll;
const ll mod=100000007;
inline ll ksm(ll x,ll y){
    rr ll ans=1;
    for (;y;y>>=1,x=x*x%mod)
        if (y&1) ans=ans*x%mod;
    return ans;
}
signed main(){
    rr int n,m; rr ll dp=0;
    scanf("%d%d",&n,&m);
    rr ll mi=ksm(2,n),dp1=0,dp2=1,c=1,jc=1;
    for (rr int i=2;i<=m;++i){
    	rr ll t=mi-i+1+mod; c=c*t%mod,jc=jc*i%mod;
    	dp=((c-dp1-dp2*(i-1)%mod*t%mod)+mod)%mod,dp2=dp1,dp1=dp;
    }
    return !printf("%lld",dp*ksm(jc,mod-2)%mod);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值