BZOJ2339: [HNOI2011]卡农
2015-12-04 21:54
351 查看
Description
Input
Output
Sample Input
Sample Output
HINT
Source
Day2
首先题目里说是无序的,但是不要管它,我们先把它看成有序的,最后除以一个m!m!即可。我们考虑补集转换,首先所有的子集个数应该是2n−12^n-1,我们定义f[i]f[i]为挑选ii个片段的合法的方案数,此时总数应该是A(2n−1,i−1)A(2^n-1,i-1)(排列数)。为什么是i−1i-1而不是ii呢?因为要保证总数是偶数,也就是说如果你确定了i−1i-1个片段第ii个片段也就确定了。而这样肯定多算了,具体来说有两部分:
1、如果前i−1i-1个已经合法,那么第ii个就是空集,这样肯定不合法,所以要减去f[i−1]f[i-1]。
2、如果根据前i−1i-1个确定出来的第ii个集合和前面的某一个重复,这样肯定是不合法的。
因为考虑顺序,所以那个和第ii个重复的集合有i−1i-1种位置,对于每种位置,当前的总数偶数去掉两个数之后还是偶数,所以剩下其他数的方案数为f[i−2]f[i-2]。然后我们需要算出有多少种可能重复的方案,因为我们已经确定了(i−2)(i-2)个位置,所以方案数为(2n−1−(i−2))(2^n-1-(i-2))。所以总体的方程就是:f[i]=A(2n−1,i−1)−f[i−1]−f[i−2]∗(2n−1−(i−2))∗(i−1)f[i]=A(2^n-1,i-1)-f[i-1]-f[i-2]*(2^n-1-(i-2))*(i-1)
最后在乘上一个m!m!关于modmod的逆元即可。
Input
Output
Sample Input
Sample Output
HINT
Source
Day2
首先题目里说是无序的,但是不要管它,我们先把它看成有序的,最后除以一个m!m!即可。我们考虑补集转换,首先所有的子集个数应该是2n−12^n-1,我们定义f[i]f[i]为挑选ii个片段的合法的方案数,此时总数应该是A(2n−1,i−1)A(2^n-1,i-1)(排列数)。为什么是i−1i-1而不是ii呢?因为要保证总数是偶数,也就是说如果你确定了i−1i-1个片段第ii个片段也就确定了。而这样肯定多算了,具体来说有两部分:
1、如果前i−1i-1个已经合法,那么第ii个就是空集,这样肯定不合法,所以要减去f[i−1]f[i-1]。
2、如果根据前i−1i-1个确定出来的第ii个集合和前面的某一个重复,这样肯定是不合法的。
因为考虑顺序,所以那个和第ii个重复的集合有i−1i-1种位置,对于每种位置,当前的总数偶数去掉两个数之后还是偶数,所以剩下其他数的方案数为f[i−2]f[i-2]。然后我们需要算出有多少种可能重复的方案,因为我们已经确定了(i−2)(i-2)个位置,所以方案数为(2n−1−(i−2))(2^n-1-(i-2))。所以总体的方程就是:f[i]=A(2n−1,i−1)−f[i−1]−f[i−2]∗(2n−1−(i−2))∗(i−1)f[i]=A(2^n-1,i-1)-f[i-1]-f[i-2]*(2^n-1-(i-2))*(i-1)
最后在乘上一个m!m!关于modmod的逆元即可。
[code]#include<cstdio> #include<cstring> #include<iostream> #include<cctype> typedef long long ll; using namespace std; const int mod=100000007; const int M=1000010; ll f[M],A[M],n,m,ans; void in(ll &x) { char t=getchar();int f=1;x=0; while(!isdigit(t)){if(t=='-')f=-1;t=getchar();} while(isdigit(t)){x=x*10+t-48;t=getchar();} x*=f; } ll power(ll a,ll b) { ll ans=1; for (;b;b>>=1,a=(a*a)%mod) if (b&1) ans=(ans*a)%mod; return ans; } void work() { A[0]=1; for (int i=1;i<=m;++i) A[i]=(A[i-1]*((ans-i+1+mod)%mod))%mod; } int main() { in(n),in(m); ans=power(2,n);--ans; if (ans<0) ans+=mod; work(); for (int i=3;i<=m;++i) f[i]=((A[i-1]-f[i-1]-(f[i-2]*(i-1)%mod*(ans-(i-2)))%mod)+mod)%mod; ans=1; for (int i=2;i<=m;++i) ans=(ans*i+mod)%mod; f[m]=(f[m]*power(ans,mod-2)%mod+mod)%mod; cout<<(f[m]+mod)%mod; return 0; }
相关文章推荐
- leetcode Binary Tree Paths
- Caffe 跑自己的数据和训练
- 【STL】STL之顺序容器:vector、deque、list、forward_list、array、string
- Android Service 启动和停止服务
- Chrome调试工具简单介绍
- 剑指offer10 矩形覆盖
- iOS 第三方库冲突的处理
- hadoop环境搭建-完全分布式
- openjudge 马走日
- 嵌套语句练习(画三角形)
- leetcode Add Digits
- 富文本编辑器在Java中使用
- Make系统变量
- IOS中Block小结
- nyoj 68三点顺序 【几何】
- Aspect Based Sentiment Analysis datasets
- 20个非常有用的Java程序片段
- Android数字游戏之数独(自动随机生成不同难度的数独)
- POJ 3279 + UVA 11464 (二维翻转水题)
- shell编程高级之正则表达式