HDU 4869 (递推 组合数取模)

Problem Turn the pokers (HDU 4869)

题目大意

  有m张牌,全为正面朝上。进行n次操作,每次可以将任意ai张反面,询问n次操作可能的状态数。

解题分析

  记正面朝上为1,朝下为0。

  若最后有x个1,则对答案的贡献为C(n,x)。所以只需要知道最后可能的1的个数。

  假设已经有a个1,某次操作可以将b张牌反面,可以发现操作之后可能的1的个数相差2。

  记录每次操作后1的个数所在区间为[l ,r],即可能取到的个数为l , l+2 , l+4 , ...... , r 。

  每次转移分类讨论一下,贪心转移即可。

参考程序

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cmath>
 4 #include <algorithm>
 5 using namespace std;
 6
 7 #define N 100008
 8 #define mo 1000000009
 9 int a[N];
10 int pa[N],pb[N];
11 int n,m;
12
13 void calc(int &l,int &r,int x){
14     int ll,rr;
15     if (x<l) ll=l-x;
16     if (l<=x && x<=r) ll=(r-x) & 1;
17     if (r<x) ll=x-r;
18
19     if (x<m-r) rr=x+r;
20     if (m-r<=x && x<=m-l) rr=m-((m-l-x) & 1);
21     if (m-l<x) rr=m-(x-(m-l));
22     l=ll; r=rr;
23 }
24
25 int  C(int x,int y){
26     return 1ll*pa[x]*pb[y] % mo *pb[x-y] % mo;
27 }
28
29 int quick_pow(int x,int y){
30     int res=1;
31     while (y){
32         if (y&1) res=1ll*res*x % mo;
33         x=1ll*x*x % mo;
34         y=y >>1;
35     }
36     return res;
37 }
38
39 int main(){
40     pa[0]=pb[0]=1;
41     for (int i=1;i<N;i++) pa[i]=(1ll*pa[i-1]*i) % mo;
42     for (int i=1;i<N;i++) pb[i]=quick_pow(pa[i],mo-2);
43     while (~scanf("%d %d",&n,&m)){
44         for (int i=1;i<=n;i++) scanf("%d",&a[i]);
45         int l=0,r=0;
46         for (int i=1;i<=n;i++) calc(l,r,a[i]);
47
48         long long ans=0;
49         for (int i=l;i<=r;i+=2)    ans= (ans+C(m,i)) % mo;
50         printf("%I64d\n",ans);
51     }
52 }

时间: 2024-12-13 15:13:29

HDU 4869 (递推 组合数取模)的相关文章

hdu 3037 Saving Beans 组合数取模模板题。。

Saving Beans Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2707    Accepted Submission(s): 1014 Problem Description Although winter is far away, squirrels have to work day and night to save b

cf166e 在四面体上寻找路线数 递推,取模

来源:codeforces                 E. Tetrahedron You are given a tetrahedron. Let's mark its vertices with letters A, B, C and D correspondingly. An ant is standing in the vertex D of the tetrahedron. The ant is quite active and he wouldn't stay idle. At

排列组合+组合数取模 HDU 5894

1 // 排列组合+组合数取模 HDU 5894 2 // 题意:n个座位不同,m个人去坐(人是一样的),每个人之间至少相隔k个座位问方案数 3 // 思路: 4 // 定好m个人 相邻人之间k个座位 剩下就剩n-(m+1)*k个座位 5 // 剩下座位去插m个不同的盒子==就等价n个相同的球放m个不同的盒子 6 // 然后组合数出来了 7 // 乘n的话是枚举座位,除m是去掉枚举第一个座位的时候,剩下人相邻的座位相对不变的情况 8 9 #include <iostream> 10 #incl

组合数取模Lucas定理及快速幂取模

组合数取模就是求的值,根据,和的取值范围不同,采取的方法也不一样. 下面,我们来看常见的两种取值情况(m.n在64位整数型范围内) (1)  , 此时较简单,在O(n2)可承受的情况下组合数的计算可以直接用杨辉三角递推,边做加法边取模. (2) ,   ,并且是素数 本文针对该取值范围较大又不太大的情况(2)进行讨论. 这个问题可以使用Lucas定理,定理描述: 其中 这样将组合数的求解分解为小问题的乘积,下面考虑计算C(ni, mi) %p. 已知C(n, m) mod p = n!/(m!(

Uva12034 (组合数取模)

题意:两匹马比赛有三种比赛结果,n匹马比赛的所有可能结果总数 解法: 设答案是f[n],则假设第一名有i个人,有C(n,i)种可能,接下来还有f(n-i)种可能性,因此答案为 ΣC(n,i)f(n-i) 另外这里给出两个求组合数的模板,卢卡斯定理的p是模数,并且要求是素数,第二个是递推式,适合于n<2000的情况 1 #include<cstdio> 2 using namespace std; 3 const int maxn = 1e3; 4 const int mod = 1005

组合数取模终极版

以前讲述过很多组合数取模问题,详见:http://blog.csdn.net/acdreamers/article/details/8037918 今天,我们继续学习一些稍有难度的组合数取模问题,比如大组合数对合数取模,求大组合数的最后位数字等等. 首先来看组合数对合数取模问题 问题:求的值,其中和,并且是合数. 分析:先把素因子分解,然后转化为求,这里为素数,然后用CRT合并.所以现在重点来研究 如何求的值.这个问题AekdyCoin大神已经详细讲述了,如下链接     链接:http://h

大组合数取模之lucas定理模板,1&lt;=n&lt;=m&lt;=1e9,1&lt;p&lt;=1e6,p必须为素数

typedef long long ll; /********************************** 大组合数取模之lucas定理模板,1<=n<=m<=1e9,1<p<=1e6,p必须为素数 输入:C(n,m)%p 调用lucas(n,m,p) 复杂度:min(m,p)*log(m) ***********************************/ //ax + by = gcd(a,b) //传入固定值a,b.放回 d=gcd(a,b), x , y

toj 4111 组合数取模 暴力分解

题目大意:组合数取模,n和m并不算大,p比较大且是合数. 思路:暴力分解+快速幂 注:暴力也是有区别的,分解质因数时可以用以下work函数,写的非常巧妙,摘录自互联网. 1 #include <iostream> 2 #include <cstring> 3 using namespace std; 4 5 typedef long long ll; 6 const ll mod = 1ll << 32; 7 const int N = 1000001; 8 const

[BZOJ 3129] [Sdoi2013] 方程 【容斥+组合数取模+中国剩余定理】

题目链接:BZOJ - 3129 题目分析 使用隔板法的思想,如果没有任何限制条件,那么方案数就是 C(m - 1, n - 1). 如果有一个限制条件是 xi >= Ai ,那么我们就可以将 m 减去 Ai - 1 ,相当于将这一部分固定分给 xi,就转化为无限制的情况了. 如果有一些限制条件是 xi <= Ai 呢?直接来求就不行了,但是注意到这样的限制不超过 8 个,我们可以使用容斥原理来求. 考虑容斥:考虑哪些限制条件被违反了,也就是说,有哪些限制为 xi <= Ai 却是 xi