zoukankan      html  css  js  c++  java
  • hdu4869 费马小+快速幂

    思路:费马小+快速幂
          无论怎么翻,每一步的1出现的可能个数的奇偶性是一样的,因为奇数 - 偶数 = 奇数,偶数 - 偶数 = 偶数,有一张牌被重叠了,那么就减去一个偶数2,所以怎么重叠都不会变(当前奇偶性与当前总翻牌数奇偶性一样),所以我们只要找到1的最大可能数,和最小可能数(当然最大和最小奇偶性一定相同),然后排列组合求和就行了,假如一共有10张牌,1出现的最大可能数是6 ,最小是2,那么ans = C(10 ,2) + C(10 ,4) + C(10 ,6).
    最大和最小之间的同奇偶的数一定可以出现,就是搓1位,自己可以画画,这样又有一个蛋疼的问题,就是排列组合必然会涉及到除法,可是除法怎么处理这个 (a / b) % c因为他不等于 (a % c) / (b % c) ,乘法还可以,其实我们可以除法转化成乘法,使得(a / b) % c = a * pow(b ,c - 2) % c,这里的c是质数,下面证明一下
    根据费马小定理有
    a^(p - 1) % p = 1 % p
    那么
    (a^(p - 1) / a) % p = (1 / p) % p  则 a^(p - 2) = (1 / a) % p
    除以a只要乘以1/a也就是乘以等号左侧,这样就把除法变成乘法。
    注意成立的原因是在本题目里 a^(p-1)/p是一个大于等于p的数。 

    对于求1可能出现的次数min ,和max,就是分情况讨论,直接看代码自己模拟一下代码就懂了,这里就不解释了,全解释了读者看完也就没意思了。  


    #include<stdio.h>
    
    #define MOD 1000000009 
    
    __int64 X[110000];
    __int64 C[110000];
    
    __int64 quick_pow(__int64 a ,__int64 b)
    {
       __int64 c =  1;
       while(b)
       {
          if(b&1) c *= a;
          a *= a ,b /= 2;
          c %= MOD ,a %= MOD;
       }
       return c;
    }
    
    int main ()
    {
       int n ,m ,i;
       while(~scanf("%d %d" ,&m ,&n))
       {
          for(i = 1 ;i <= m ;i ++)
          scanf("%I64d" ,&X[i]);
          
          __int64 MIN = 0 ,MAX = 0;
          for(i = 1 ;i <= m ;i ++)
          {
             __int64 mi ,ma;
             if(X[i] <= MIN) mi = MIN - X[i];
             else if(X[i] > MAX) mi = X[i] - MAX;
             else mi = (X[i]&1) != (MIN&1);
             
             if(X[i] + MAX <= n) ma = X[i] + MAX;
             else if(X[i] + MIN > n) ma = n * 2 - (MIN + X[i]);
             else ma = ((X[i] + MIN) & 1) == (n & 1) ? n : n - 1;
             MAX = ma ,MIN = mi;
          }
         
          __int64 sum = 0;
          C[0] = 1;
          if(MIN == 0) sum ++;
          for(i = 1 ;i <= MAX ;i ++)
          {
             if(n - i < i) C[i] = C[n-i];
             else 
             C[i] = C[i-1] * (n - i + 1) % MOD * quick_pow(i ,MOD - 2) % MOD;
             if(i >= MIN && (i&1) == (MIN&1))
             sum  = (sum + C[i]) % MOD;   
          }
          printf("%I64d
    " ,sum);
       }
       return 0;
    }
          
    
        

  • 相关阅读:
    Hibernate 事务和并发控制
    InfoSYS-20170114
    STM32学习笔记:读写内部Flash(介绍+附代码)
    STM32串口通信配置(USART1+USART2+USART3+UART4)
    Keil-MDK编译完成后代码大小
    STM32窗口看门狗和独立看门狗的区别,看门狗介绍及代码演示
    关于单片机编程里面调用sprintf死机的解决方法及原因分析
    ESP8266 wifi 模块配置,Wechat+APP控制实现
    STM32常见问题
    深入浅出 TCP/IP 协议
  • 原文地址:https://www.cnblogs.com/csnd/p/12062932.html
Copyright © 2011-2022 走看看