【洛谷3214】[HNOI2011] 卡农(思维)

点此看题面

  • 问有多少种大小为(m)、值域为([1,2^n))的无序且无重复元素的集合,满足其中所有数异或和为(0)
  • (n,mle10^6)

巧妙的计数思想

首先,由于集合中元素不重复,方便起见我们可以改成求有序集合数,只要最后给答案除以一个(m!)即可。

(f_i)表示大小为(i)的集合个数。

考虑我们随意选择前(i-1)个数(方案数为(A_{2^n-1}^{i-1})),由于异或和要为(0),那么第(i)位上的数就唯一确定了,但它并不一定满足题目中对集合的两个限制:

  1. 它不能为(0)
  2. 它不能与选中的数重复。

容易发现,因为选中的数中不可能存在(0),是没有同时违反这两个限制的情况的,故可以分别考虑。

如果它是(0),说明选中的这(i-1)个数异或和为(0)。这种情况的方案数正是(f_{i-1})

如果它与某个选中的数重复(假设编号为(j)),那么除(i,j)以外的这(i-2)个数异或和也必须是(0)。这种情况方案数是(f_{i-2}),而(j)的选择有(i-1)种,对于确定的(i-2)个数(i)的取值有((2^n-1)-(i-2))种。

因此,得到最终的计算式:

[f_i=A_{2^n-1}^{i-1}-f_{i-1}-f_{i-2} imes (i-1) imes((2^n-1)-i+2) ]

注意,其中的排列下标都是(2^n-1),因此可以线性预处理。

代码:(O(logn+m))

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 1000000
#define X 100000007
using namespace std;
int n,m,A[N+5],f[N+5];
I int QP(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
int main()
{
	RI i,p;for(scanf("%d%d",&n,&m),p=QP(2,n)-1,A[0]=i=1;i<=m;++i) A[i]=1LL*A[i-1]*(p-i+1)%X;//预处理排列
	for(f[0]=1,f[1]=0,i=2;i<=m;++i) f[i]=(0LL+A[i-1]-f[i-1]-1LL*f[i-2]*(i-1)%X*(p-i+2)%X+2*X)%X;//递推
	RI t=1;for(i=1;i<=m;++i) t=1LL*t*i%X;return printf("%d
",1LL*f[m]*QP(t,X-2)%X),0;//有序化无序
}
败得义无反顾,弱得一无是处
原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu3214.html