HDOJ--4869--Turn the pokers【组合数学+快速幂】

题意:有m张扑克,开始时全部正面朝下,你可以翻n次牌,每次可以翻xi张,翻拍规则就是正面朝下变背面朝下,反之亦然,问经过n次翻牌后牌的朝向有多少种情况。我们可以把正面朝上理解为1,反面朝上理解为0,那么可以理解为求01串的不同的组合方式有几种。

解题思路:我们可以知道,每张牌假设起始状态都为0,如果翻奇数次,该牌最后的情况是1,如果翻偶数次,该牌的最后情况为0.根据n次翻牌的个数找出1的个数的下限和上限,然后再在这个范围里用组合数学求有几种排列即可。

我们先来看怎么求1的个数的上限和下限:

Minm:下限  maxm:上限  p:当前的下限 q:当前的上限

1.求1的个数的下限:

当前下限大于等于现在翻牌的数量,这个比较好理解,全翻1,1变成0,则剩下的1就是minm-x;

当前下限小于翻牌数量,上限大于等于翻牌数量,即翻牌数量刚好在上下限之间,所以最少可以把正面朝上的数量减为零,但不一定能减到0,因为有可能当前正面朝上的牌时奇数,而翻牌数量是偶数,所以要判断奇偶性是否一样,为什么要和minm比较奇偶性。如果奇偶性相同,可以减为0,

否则,应该为1。

翻牌数量比上限还大的时候,直接减去上限就是下限。

2.求1的个数的上限:

上限+翻牌数量没有达到总牌数时,上限+翻牌数量就是新的上限,全翻0,这样使1最多;

上限+翻牌数量大于总牌数,而下限+翻牌数量小于等于总牌数,前者可以说是翻牌溢出了,已经全是1再翻的话只会让一些1变成0,后者没有达到全变成1的情况。它们是一个上限一个下限,这说明可以处理到在这之间的情况,那么最好的结果是所有牌都正面朝上,全是1,需要判断奇偶性是否一致,这回和m比较。

上限+翻牌数、下限+翻牌数全都大于总牌数时,说明都会溢出,那就用2 * m - (x + minm)来表示上限,因为(x+minm)小,所以溢出的1变成0的牌数少。

接下来要处理的是计算出 c ( m , i ) 的值:

由于数比较大,要对1000000009取余,这里要用到快速幂取余:

模板如下:

  1. long long  PowerMod (int a, int b, int c)
  2. {
  3. int  ans = 1;
  4. a = a % c;
  5. while(b>0) {
  6. if(b % 2 = = 1)
  7. ans = (ans * a) % c;
  8. b = b/2;       //   b>>=1;
  9. a = (a * a) % c;
  10. }
  11. return ans;
  12. }

关于快速幂取余,可以查看链接:http://blog.csdn.net/acm_code/article/details/38270829

用数组c表示组合数学 c ( m , i ) 的值, 按理说 c[ i ] = c[ i - 1 ] * ( m - i + 1 ) / i ,然后这个数对MOD取模,但是存在除法取模就不是这么简单的分解了,费马小定理是这样: a^(p-1) ≡1(mod p),p为质数,a、p互质,a^(p-1) mod p 恒等于1。

变换一下,两边同时除以a ,变成 a^(p-2)=a^(-1)(mod p),所以要除以a 就可以表示成 乘  a^(p-2),所以有了这样的写法:c[i] = c[i-1] * (m-i+1) % MOD * PowerMod(i,MOD-2) % MOD;

最后将组合数学值相加的时候,要隔一个相加,不难发现上限和下限的奇偶性一样。

总和一下上述思想,我们可以写出代码:

  1. #include<stdio.h>
  2. #define MOD 1000000009
  3. __int64 c[];
  4. __int64 mode(__int64 a,int n)
  5. {
  6. __int64 t = a;
  7. __int64 ans = ;
  8. while(n)
  9. {
  10. if(n & )
  11. {
  12. ans = ans * t % MOD;
  13. }
  14. n >>= ;
  15. t = t * t % MOD;
  16. }
  17. return ans;
  18. }
  19. int main()
  20. {
  21. int minm,maxm,x;
  22. int p,q;
  23. int n,m;
  24. while(scanf("%d%d",&n,&m)!=EOF)
  25. {
  26. //初始状态下1的上限和下限都为0;
  27. minm = maxm = ;//maxm表示上限,minm表示下限
  28. p = q = ;//p、q分别记录当前下,上限,然后更新到minm、maxm中
  29. for(int i=; i<n; i++)
  30. {
  31. scanf("%d",&x);//第i次翻牌的数量
  32. //判断下限
  33. if(minm>=x)//当前下限大于等于现在翻牌的数量
  34. p = minm - x;//全翻1,1变成0,则剩下的1就是minm-x
  35.  
  36. else if(maxm>=x)//当前下限小于翻牌数量,上限大于等于翻牌数量,
  37. p = ((x&)==(minm&))?:; //x与minm同奇偶就为0 ,否则为1
  38.  
  39. else//翻牌数量比上限还大的时候,直接减去上限就是下限
  40. p = x - maxm;
  41.  
  42. //判断上限
  43. if(maxm+x<=m)//上限+翻牌数量没有达到总牌数时,上限+翻牌数量就是新的上限
  44. q = maxm + x;
  45.  
  46. else if(minm+x<=m) //上限+翻牌数量大于总牌数,而下限+翻牌数量小于等于总牌数
  47. q = (((minm+x)&)==(m&))?m:m-;//x与minm同奇偶就为0,否则为1
  48.  
  49. else//上限+翻牌数、下限+翻牌数全都大于总牌数
  50. q = * m - (x + minm);
  51.  
  52. minm = p;
  53. maxm = q;
  54. }
  55. __int64 sum=;
  56. c[]=;
  57. for(int i=; i<=maxm; i++)//求C(m,i);
  58. {
  59. if(m-i<i)
  60. c[i] = c[m-i];
  61. else
  62. {
  63. c[i] = c[i-]*(m-i+)%MOD*mode((__int64)i,MOD-)%MOD;
  64. }
  65. }
  66. for(int i=minm; i<=maxm; i+=)
  67. {
  68. sum+=c[i];
  69. sum%=MOD;
  70. }
  71. printf("%I64d\n",sum);
  72. }
  73. return ;
  74. }

HDU 4869 Turn the pokers (2014 多校联合第一场 I)的更多相关文章

  1. HDU 4869 Turn the pokers (2014多校联合训练第一场1009) 解题报告(维护区间 + 组合数)

    Turn the pokers Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  2. HDU 4865 Peter's Hobby(2014 多校联合第一场 E)(概率dp)

    题意:已知昨天天气与今天天气状况的概率关系(wePro),和今天天气状态和叶子湿度的概率关系(lePro)第一天为sunny 概率为 0.63,cloudy 概率 0.17,rainny 概率 0.2 ...

  3. hdu 4869 Turn the pokers (2014多校联合第一场 I)

    Turn the pokers Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  4. HDU 4869 Turn the pokers (2014 Multi-University Training Contest 1)

    Turn the pokers Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)T ...

  5. hdu 4865 Peter&#39;s Hobby(2014 多校联合第一场 E)

    Peter's Hobby Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) To ...

  6. HDU 4870 Rating (2014 多校联合第一场 J)(概率)

    题意: 一个人有两个TC的账号,一开始两个账号rating都是0,然后每次它会选择里面rating较小的一个账号去打比赛,每次比赛有p的概率+1分,有1-p的概率-2分,当然如果本身是<=2分的 ...

  7. HDU 4868 Information Extraction(2014 多校联合第一场 H)

    看到这道题时我的内心是奔溃的,没有了解过HTML,只能靠窝的渣渣英语一点一点翻译啊TT. Information Extraction 题意:(纯手工翻译,有些用词可能在html中不是一样的,还多包涵 ...

  8. HDU 4869 Turn the pokers(推理)

    HDU 4869 Turn the pokers 题目链接 题意:给定n个翻转扑克方式,每次方式相应能够选择当中xi张进行翻转.一共同拥有m张牌.问最后翻转之后的情况数 思路:对于每一些翻转,假设能确 ...

  9. hdu 5288||2015多校联合第一场1001题

    pid=5288">http://acm.hdu.edu.cn/showproblem.php?pid=5288 Problem Description OO has got a ar ...

随机推荐

  1. 将时间显示为“刚刚”“n分钟/小时前”等

    在很多场合为了显示出信息的及时性,一般会将时间显示成“刚刚”,“5分钟前”,“3小时前”等,而不是直接将时间打印出来.比如微博,SNS类应用就最长用到这个功能.而一般存储在数据库中的时间格式为 Uni ...

  2. POJ 1041 John's trip 无向图的【欧拉回路】路径输出

    欧拉回路第一题TVT 本题的一个小技巧在于: [建立一个存放点与边关系的邻接矩阵] 1.先判断是否存在欧拉路径 无向图: 欧拉回路:连通 + 所有定点的度为偶数 欧拉路径:连通 + 除源点和终点外都为 ...

  3. iPhone开发技巧之日志保存教程

    http://mobile.51cto.com/iphone-283337.htm Objective-C开发程序的时候,有专门的日志操作类NSLog,它将指定的输出到标准的错误输出上(stderr) ...

  4. 在springmvc中controller的一个方法处理多个不同请求

    value的uri值为以下三类: A) 可以指定为普通的具体值: B)  可以指定为含有某变量的一类值(URI Template Patterns with Path Variables): @Req ...

  5. 使用contentprovider实现的日记(转)

    目录结构: MyDiaryActivity.java package com.zhang.myDiary; import com.zhang.myDiary.DiaryColumn.DiaryClmn ...

  6. POJ 3090 Visible Lattice Points 欧拉函数

    链接:http://poj.org/problem?id=3090 题意:在坐标系中,从横纵坐标 0 ≤ x, y ≤ N中的点中选择点,而且这些点与(0,0)的连点不经过其它的点. 思路:显而易见, ...

  7. MFC 只启动一个程序实例

    问题描述: 我们开发过程中可能会经常遇到,只启动一个程序实例.即一个程序启动之后,如果再次执行该程序,将会恢复之前打开的程序,而不是打开一个新的程序. 实现原理:利用FindWindow/FindWi ...

  8. 设置HTTP代理

    Maven通过<<UserHome>>/.m2/settings.xml(如果没有该文件,复制<<MavenHome>>/conf/settings.x ...

  9. JS实现图片翻书效果

    picture.html <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http- ...

  10. Java读写Word文件常用技术

      Java操作操作Word文件,最近花了几天时间解决使用Word模板导出数据的问题,收集到一些资料分享下. 常见的技术如下: 1.POI(兼容doc.docx文件) 官方网站:http://poi. ...