zoukankan      html  css  js  c++  java
  • HDU 5446 Unknown Treasure(lucas + 中国剩余定理 + 模拟乘法)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5446

    题目大意:求C(n, m) % M, 其中M为不同素数的乘积,即M=p1*p2*...*pk, 1≤k≤10。1mn10^18。

    分析: 如果M是素数,则可以直接用lucas定理来做,但是M不是素数,而是素数的连乘积。令C(n, m)为 X ,则可以利用lucas定理分别计算出 X%p1,X%p2, ... , X % pk的值,然后用中国剩余定理来组合得到所求结果。

    比较坑的地方是,中间结果会超long long 范围,要用类似于快速幂的方法来模拟。

    参考代码:

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <string.h>
     4 using namespace std;
     5 long long a[110001];
     6 long long Mod;
     7 long long c[110001];
     8 long long w[1000];
     9 long long Egcd(long long a,long long b,long long &x,long long &y){
    10     long long d;
    11     if(b==0){
    12         x=1;y=0;
    13         return a;
    14     }
    15     d=Egcd(b,a%b,y,x);
    16     y-=a/b*x;
    17     return d;
    18 }
    19 long long cal(long long a, long long b, long long mod) {//模拟a*b%mod
    20     long long ret = 0;
    21     while(b) {
    22         if(b & 1) ret = (ret + a) % mod;
    23         a = (a + a) % mod;
    24         b >>= 1;
    25     }
    26     return ret;
    27 }
    28 
    29 long long c_r(int len){//中国剩余定理
    30     int i;
    31     long long d,x,y,n,m,ret;
    32     ret=0;
    33     n=1;
    34     for(i=0;i<len;i++)
    35         n*=c[i];
    36     for(i=0;i<len;i++){
    37         m=n/c[i];
    38         d=Egcd(m,c[i],y,x);
    39         y=(c[i]+y%c[i])%c[i];
    40         if( i&1) y -= c[i];
    41         //if(y>c[i]-y) y=y-c[i];
    42         ret=(ret+cal(y*m, w[i], n))%n;
    43     }
    44     return (n+ret%n)%n;
    45 }
    46 
    47 void init(){
    48     int i;
    49     memset(a, 0, sizeof(a));
    50     a[0]=1;
    51     for(i=1;i<Mod;i++)
    52         a[i]=a[i-1]*i%Mod;
    53 }
    54 
    55 long long gcd(long long a,long long b){
    56     if(b==0) return a;
    57     return gcd(b,a%b);
    58 }
    59 
    60 long long choose(long long n,long long m){
    61     if(m>n)return 0;
    62     else if(n==m) return 1;
    63     long long nn=a[n],mm=a[m]*a[n-m]%Mod;
    64     long long d=gcd(nn,mm);
    65     nn/=d;
    66     mm/=d;
    67     long long x,y;
    68     Egcd(mm,Mod,x,y);
    69     x=(x+Mod)%Mod;
    70     return (x*nn)%Mod;
    71 }
    72 
    73 long long work(long long n,long long m){//lucas
    74     long long ret=1;
    75     while(n&&m){
    76         ret*=choose(n%Mod,m%Mod);
    77         ret%=Mod;
    78         n/=Mod,m/=Mod;
    79     }
    80     return ret;
    81 }
    82 
    83 int main(){
    84     int T;
    85     long long n,m;
    86     int k;
    87     scanf("%d",&T);
    88     while(T--){
    89         cin >> n >> m >> k;
    90         if(m > n-m) m = n-m;
    91         for(int i=0;i<k;i++){
    92             cin >> c[i];
    93             Mod=c[i];
    94             init();
    95             w[i]=work(n,m);
    96         }
    97         cout << c_r(k) << endl;
    98     }
    99 }
  • 相关阅读:
    JSP中的一个树型结构
    访问SAP的RFC
    MySQL InnoDB的一些参数说明
    Python: 去掉字符串中的非数字(或非字母)字符
    获取百度地图代码方法
    ps修图之——四步去修图后的毛边
    Python中给文件加锁
    问答项目---金币经验奖励规则及网站配置写入config文件
    问答项目---封装打印数组的方法
    问答项目---栏目增删改方法示例
  • 原文地址:https://www.cnblogs.com/beisong/p/4805710.html
Copyright © 2011-2022 走看看