ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P3214 [HNOI2011] 卡农 (dp +排列计数 正难则反)

2022-09-06 00:02:46  阅读:219  来源: 互联网

标签:方案 int 选取 偶数 P3214 HNOI2011 子集 我们 卡农


 

题目传送门

题目大意:

给定两个数 \(n , m\) ,在集合 \(S = {1,2...n}\) 中选取 \(m\) 个非空子集,使得子集不重复并且子集中的每个元素出现偶数次,求出满足上述条件的方案数。
假设 \(a\) 为 \(\{\{1,2\},\{2,3\}\}\),\(b\) 为 \(\{\{2,3\},\{1,2\}\}\),那么 \(a\) 与 \(b\) 为重复情况。(笔者定义这种情况为假相同)

题目分析:

  • [\(1\)]:正难则反。我们分析题目中的条件,首先对于偶数次的情况来说还算好处理,对于重复的情况,我们是否能够方便快速的处理这种情况呢,对于笔者来说太难了,在笔者的知识范围内计数问题不是计数 \(dp\) 就是组合数学,那么运用组合数学的知识需要去掉某个集合重复 \(2,3,4...n\)次的情况,所以我们不考虑,那么对于 \(dp\) 来说,我们可以设计出 \(dp_{i,j}\) 为前 \(i\) 中子集取了 \(j\) 个子集的方案数,而 \(i\) 又太大了所以说放弃,我们来考虑用 总方案数 \(-\) 不合法的方案数 (欢迎各位大佬指出错误)

  • [\(2\)]:首先我们考虑,\(S\) 的子集有多少种,根据二项式定理可知, \(S\) 的子集有 \(2^n - 1\) 种。那么我们不考虑假相同的情况,因为这个可以再最后直接除 \(m!\) 的阶乘来处理,在这种情况下总方案数为 \(A_{2^n-1}^m\)。

  • [\(3\)]:我们在 \(1\) 的基础上来考虑出现偶数次如何处理。对于一个选取 \(i\) 个子集使子集中所有元素出现次数为偶数的情况,我们可以由选取 \(i - 1\) 个子集出现次数不固定的方案数来确定。因为对于选取 \(i - 1\) 个子集的时候,对于出现偶数次的元素在第 \(i\) 个子集中一定不会出现,对于奇数次的元素在第 \(i\) 个集合中一定会出现,那么第 \(i\) 个集合就固定下来了,所以我们只需求出选取 \(i - 1\) 个子集的总方案数即可,为 \(A_{2^n - 1}^{i-1}\)。

  • [\(4\)]:我们定义 \(f_i\) 为选取 \(i\) 个子集的方案数。接下来我们来考虑非空的情况,若我们在第 \(i\) 个子集选取了一个空集,那么这个空集对方案数不产生影响,故我们只需去掉 \(f_{i - 1}\) 即可。

  • [\(5\)]:最后我们来处理子集重复的情况。若我们选的第 \(i\) 个子集与前面某个子集 \(j\) 重复,那么 \(i\) 的取值有 \(i - 1\)种,而去掉子集 \(i , j\) 所能构成的合法方案数为 \(f_{i,j}\),最后思考 \(j\) 有多少种取值,我们一共有 \(2^n - 1\) 个子集,而前面用掉了 \(i - 2\) 个,故 \(j\) 的选取有 \(2^n-1-(i - 2)\) 种。那么我可可得递推式 \(f_i = A_{2^n-1}^{i-1} - f_{i - 1} - (i - 1) *(2^n-1-(i - 2)) * f_{i - 2}\)

代码实现:

我们只需要处理出 \(2^n-1\) , \(m!\), \(A_{2^n-1}^i\)即可,最后处理一下逆元,用 \(f_m * \frac{1}{m!}\) 即可

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod = 1e8 + 7;
const int M = 1e6 + 7; 
int f[M] , A[M];
int Pow(int a, int b) {
	int ans = 1;
	while(b) {
		if(b & 1) ans = ans * a % mod;
		a = a * a % mod;
		b >>= 1;	
	}
	return ans;
}	
signed main () {
	int n , m; cin >> n >> m;
	int _2 = 1;
	for(int i = 1; i <= n; ++ i) _2 = _2 * 2 % mod;
	_2 = (_2 + mod - 1) % mod;
	A[0] = 1;
	int jc = 1;
	for(int i = 1; i <= m; ++ i) A[i] = A[i - 1] * ((_2 - i + 1 + mod) % mod) % mod , jc = jc * i % mod;
	f[f[1] = 0] = 1;
	for(int i = 2; i <= m; ++ i) f[i] = (A[i - 1] - f[i - 1] + mod - f[i - 2] * (i - 1) % mod * (_2 - i + 2 + mod) % mod + mod) % mod;
	cout << f[m] * Pow(jc , mod - 2) % mod;
}

[========]

完结!

标签:方案,int,选取,偶数,P3214,HNOI2011,子集,我们,卡农
来源: https://www.cnblogs.com/Love-yx/p/16660134.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有