P3214 [HNOI2011] 卡农

P3214 [HNOI2011] 卡农

考虑将前面 \(m-1\) 个集合放好后,最后一个集合由于需要满足所有元素出现次数为偶数,只有一种填法。对于一些特殊的前面 \(m-1\) 个集合,最后一个集合无解。

考虑哪些前面的集合会使得最后一个集合不合法。

  • 前面 \(m-1\) 个集合恰好使得每个元素出现次数均为偶数。
  • 当前元素出现次数为奇数的集合在前面 \(m-1\) 个集合中已经出现,此时将这个集合去掉后一定使得每个元素的出现次数为偶数。

去掉重新排列后相同的限制,最后除以 \(m!\) 即可。

考虑设 \(f_i\) 表示放置 \(i\) 个集合的答案。则有

\[f_i=\binom{(2^n-1)}{i-1}\times (i-1)!-f_{i-1}-(i-1)(2^n-1-(i-2))\times f_{i-2} \]

其中 \(f_0=1,f_1=0\)

化简式子,得到

\[f_i=\frac{(2^n-1)!}{(2^n-i)!}-f_{i-1}-(i-1)(2^n-1-(i-2))\times f_{i-2} \]

时间复杂度 \(\mathcal{O}(m+\log p)\)

code
#include<bits/stdc++.h>
using namespace std;
namespace IO{
	template<typename T>inline bool read(T &x){
		x=0;
		char ch=getchar();
		bool flag=0,ret=0;
		while(ch<'0'||ch>'9') flag=flag||(ch=='-'),ch=getchar();
		while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(),ret=1;
		x=flag?-x:x;
        return ret;
	}
	template<typename T,typename ...Args>inline bool read(T& a,Args& ...args){
	    return read(a)&&read(args...);
	}
	template<typename T>void prt(T x){
		if(x>9) prt(x/10);
		putchar(x%10+'0');
	}
	template<typename T>inline void put(T x){
		if(x<0) putchar('-'),x=-x;
		prt(x);
	}
	template<typename T>inline void put(char ch,T x){
		if(x<0) putchar('-'),x=-x;
		prt(x);
		putchar(ch);
	}
	template<typename T,typename ...Args>inline void put(T a,Args ...args){
	    put(a);
		put(args...);
	}
	template<typename T,typename ...Args>inline void put(const char ch,T a,Args ...args){
	    put(ch,a);
		put(ch,args...);
	}
	inline void put(string s){
		for(int i=0,sz=s.length();i<sz;i++) putchar(s[i]);
	}
	inline void put(const char* s){
		for(int i=0,sz=strlen(s);i<sz;i++) putchar(s[i]);
	}
}
using namespace IO;
#define mod 100000007
int f[1000005],n,m,siz,prod,ifac=1;
inline int add(int x,int y){
	return (x+y)>=mod?x+y-mod:x+y;
}
inline int mul(int x,int y){
	return (long long)x*y%mod;
}
inline int power(int x,int y){
	int res=1;
	while(y){
		if(y&1) res=mul(res,x);
		x=mul(x,x);
		y>>=1; 
	}
	return res;
}
int main(){
	read(n,m);
	siz=add(power(2,n),mod-1);
	for(int i=1;i<=m;i++) ifac=mul(ifac,i);
	f[0]=1,f[1]=0,prod=1;
	for(int i=2;i<=m;i++){
		prod=mul(prod,siz-i+2);
		int tmp=add(f[i-1],mul(mul(i-1,siz-i+2),f[i-2]));
		f[i]=add(prod,mod-tmp);
	}
	put('\n',mul(f[m],power(ifac,mod-2)));
	return 0;
}
posted @ 2022-10-06 16:39  fzj2007  阅读(26)  评论(0编辑  收藏  举报