zoukankan      html  css  js  c++  java
  • HDU 4869 Turn the pokers

    看完题解还wa了老半天才ac = =!囧rz 给大牛门跪了

    因为本题求的是最后状态的种数,设最终翻到正面为1,反面为0:

    因为每次翻牌的选择自由,所以一定范围内,翻到正面的牌数相差2的状态都可以取到;

    (假设当前状态为i 个1,可以用一次翻到1的机会把另一个翻到1的牌翻到0;这样状态就是i-2,相差2了;同理可得i+2(设i,i-2,i+2都在范围内)

    接下来就是求这个范围(1的个数)了:

    设l 为范围的下界,r 为范围的上界;nl 为当前下界,nl 为当前上界;

    当前可翻牌数为x ;

    求下界:

    若 x<=l :nl = l-x;l 为前一次翻完后1的个数的最小值,若x<l,当前最小值便是 l-x;(把1翻为0)

    若 x>l && x<=r : nl = ( l &1 == x&1)?0:1;前一次翻完后状态可以为l,r 中间相差为2的所有值,所以当x与l,r相差为2的倍数时,为0,否则为1;

    若 x>r :nl = x-r ; 若x比最大值还大,则把所有1翻为0后又要把 x-r个0翻为1;

    求上界:

    若 x+r<=m :nr=x+r;x加上最大值小于总数时,当前最大值就是 x+r;

    若 x+r>m && x+l<=m:nr = (x+l )&1==m&1?m:m-1;前一次翻完后状态可以为l,r中间相差为2的所有值,所以当x+l 与m相差为2的倍数时,存在k,使x+k==m,否则只有 x+k==m-1,或x+k==m+1;

    若 x+l>m :nr=m-(x+l-m)=m*2-(x+l);若x+l>m,则把所有0翻为1后还需把x+l-m个1翻为0;

    知道范围后便是求所有状态的种数了,即组合排列问题;

    一般来说,c(m,i)=c(m,i-1)*(m-i+1)/i;

    但是本题为取模题;除法的取模运算并不像乘法一样简单;所以我们利用费马小定理来把除法取模转化为乘法:

    费马小定理:a^(p-1)≡1(mod p);  p为质数;

    所以 a^(p-2)=a^-1 (mod p) 

    所以 原式中 /i 的部分可以转化为 *i^-1(mod p)=*i^(p-2) (mod p)

    因为本题为模 1e9+9,是质数。。。所以p=1e9+9;

    这部分可以用快速幂取模来得到;

    所以 c(m,i)=c(m,i-1)*(m-i+1)  *i^(p-2) ;

    即 c(m,i)=c(m,i-1)*(m-i+1) %p *pow_mode (i,p-2) %p ;

    ps:开始wa到不行,所以从大牛们博客里扒了些代码混杂自己的代码交上去a过一发 orz;发现错误后,看懂题解后自己又写了一发交上去了;

    这是自己写的,居然也还改了两三次 囧rz

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 using namespace std;
     5 
     6 typedef long long ll;
     7 
     8 const ll mod = 1e9+9;
     9 
    10 ll pow_mode (ll a,ll b){
    11     ll temp=a;
    12     ll s=1;
    13     while (b){
    14         if (b&1)
    15             s=(s*temp)%mod;
    16         b/=2;
    17         temp=(temp*temp)%mod;
    18     }
    19     return s;
    20 }
    21 
    22 int main (){
    23     ll n,m;
    24     ll c[100005];
    25     while (cin>>n>>m){
    26         ll x,ans;
    27         ll l,r,nl,nr;
    28         l=r=nl=nr=0;
    29         while (n--){
    30             cin>>x;
    31             if (x<=l) nl=l-x;
    32             else if (x<=r) nl=(x&1)==(l&1)?0:1;
    33             else nl=x-r;
    34             if (r+x<=m) nr=r+x;
    35             else if (l+x<=m) nr=((l+x)&1)==(m&1)?m:m-1;
    36             else nr=m*2-(l+x);
    37             l=nl;r=nr;
    38         }//cout<<l<<" "<<r<<endl;
    39         c[0]=1;
    40         ans=0;
    41         for (int i=0;i<=r;i++){
    42             if (i){
    43                 if (i*2<=m)
    44                     c[i]=((c[i-1]*(m-i+1))%mod*pow_mode (i,mod-2))%mod;
    45                 else c[i]=c[m-i];
    46             }
    47             if ((i&1)==(l&1)&&i>=l)
    48                 ans=(ans+c[i])%mod;
    49         }
    50         cout<<ans%mod<<endl;
    51     }
    52     return 0;
    53 }
  • 相关阅读:
    学习笔记之C++ How to Program(part)
    Makefile相关资料
    [ZZ]指针Guide
    [ZZ]make命令与makefile文件的写法
    SQLite数据库简介及资源下载
    程序员天生码农命?
    Application标签中有三个事件运行顺序
    Flex 项目案例集锦
    flex简介
    Flex连接数据库三种方法
  • 原文地址:https://www.cnblogs.com/gfc-g/p/3871504.html
Copyright © 2011-2022 走看看