[HNOI2011] 卡农
https://www.luogu.com.cn/problem/P3214
Solution
很经典的题目啊。
其实题目本质上,就是从 $2^n-1$ 个集合中选,有四个限制:
- 无序
- 集合非空
- 每个音阶出现的次数为偶数
- 每个集合不相同
令 $f_i$ 表示选了 $i$ 个集合,满足上面的要求。
首先考虑第三个限制,利用容斥的思想,其实只要随意选 $i-1$ 个集合,就能唯一确定剩下的那个集合使得满足第三个限制。
但是如果要满足无序的话就很烦。考虑把无序转化为有序,不管这个限制,最后除以 $m!$ 。
回到前文,现在我们不保证无序后,选择的集合数量为 $A_{2^n-1}^{i-1}$ 。然后我们还要保证剩下那个集合不是空集。只要前 $i-1$ 个不满足出现的次数为偶数即可,减去 $f_{i-1}$。
回来看还有一个限制,就是每个集合不相同,只可能是前 $i-1$ 个中的一个和第 $i$ 个集合相同。这样子剩下的 $i-2$ 个集合一定满足所有限制,也就是有 $f_{i-2}$ 个,相同的集合从 $i-1$ 里选,有 $2^n-1-(i-2)$ 中可能的取值。
把上面合起来,就是 $f_i=A_{2^n-1}^{i-1}-f_{i-1}-f_{i-2}\times (i-1)\times (2^n-1-(i-2))$。
复杂度 $O(n+m)$。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| #include<bits/stdc++.h> #define int long long #define ull unsigned long long #define maxn 1000005 #define put() putchar('\n') #define Tp template<typename Ty> #define Ts template<typename Ty,typename... Ar> using namespace std; void read(int &x){ int f=1;x=0;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();} x*=f; } namespace Debug{ Tp void _debug(char* f,Ty t){cerr<<f<<'='<<t<<endl;} Ts void _debug(char* f,Ty x,Ar... y){while(*f!=',') cerr<<*f++;cerr<<'='<<x<<",";_debug(f+1,y...);} Tp ostream& operator<<(ostream& os,vector<Ty>& V){os<<"[";for(auto& vv:V) os<<vv<<",";os<<"]";return os;} #define gdb(...) _debug((char*)#__VA_ARGS__,__VA_ARGS__) }using namespace Debug; #define fi first #define se second #define mk make_pair const int mod=1e8+7; int power(int x,int y=mod-2) { int sum=1; while (y) { if (y&1) sum=sum*x%mod; x=x*x%mod;y>>=1; } return sum; } int A[maxn],f[maxn],pw[maxn]; int n,m; signed main(void){ int i; read(n);read(m); for (pw[0]=1,i=1;i<=n;i++) pw[i]=pw[i-1]*2%mod; int res=pw[n]-1; for (A[0]=1,i=1;i<=m;i++) A[i]=A[i-1]*(res-i+1)%mod; f[0]=1; for (i=1;i<=m;i++) { f[i]=(A[i-1]-f[i-1]-f[i-2]*(i-1)%mod*(pw[n]-i+1+mod)%mod+mod*2)%mod; } int tmp=1;for (i=1;i<=m;i++) tmp=tmp*i%mod; printf("%lld",f[m]*power(tmp)%mod); return 0; }
|