zoukankan      html  css  js  c++  java
  • bzoj 2142 国家集训队试题 礼物

    问题转化成求C(N,M) mod P p为非素数,那么我们可以将P分解质因数,

    也就是 π pi^ci的形式,因为这些pi^ci是互质的,所以我们可以用crt将他们合并

    那么问题就转化成了快速求C(N,M) mod pi^ci

    那么我们看下c的形式,为N!/(M!(N-M)!) mod pi^ci

    因为mod的数不是质数,所以分母没法正常求逆元,那么我们可以将分子分母

    中的pi的值挑出,那么我们先求N!,可以发现,N!mod pi^ci可以分段,每段是

    pi^ci长,这一段的值是0--(pi^ci-1),那么因为我们需要将N!中pi|I的挑出来

    剩下一些数,那就是好几段这个数相乘,用快速幂解决就行了,设cnt为p!其中

    不包括pi|n的

    那么N! mod pi^ci就变成了cnt^x*pi^y,那么x,y我们可以求出来,然后div掉p

    之后,就又出现了一个阶乘,那么递归去做就行了。

    比如N=11 pi=2 ci=2

    N!为1*2*3*4*5*6*7*8*9*10*11

    那么就是[1*3]*[5*7]*[9*11] mod pi^ci

    挑出来的数是2,4,6,8,10,都div pi之后是

    1,2,3,4,5 然后就成一个子问题了。

    /**************************************************************
        Problem: 2142
        User: BLADEVIL
        Language: Pascal
        Result: Accepted
        Time:492 ms
        Memory:228 kb
    ****************************************************************/
     
    //By BLADEVIL
    var
        m, n                                :longint;
        pj, c                               :array[0..110] of longint;
        pi, s, a                            :array[0..110] of int64;
        p                                   :int64;
        tot                                 :longint;
      
    procedure divide(p:int64);
    var   
        i, j                                :longint;
          
    begin
        tot:=0;
        for i:=2 to trunc(sqrt(p)) do
        if p mod i=0 then
        begin
            inc(tot);
            pj[tot]:=i;
            while p mod i=0 do
            begin
                    inc(c[tot]);
                    p:=p div i;
            end;
        end;
        if p>1 then
        begin
            inc(tot);
            pj[tot]:=p;
            c[tot]:=1;
        end;
        for i:=1 to tot do
        begin
            pi[i]:=1;
            for j:=1 to c[i] do pi[i]:=pi[i]*pj[i];
        end;
    end;
      
    function ex_gcd(a,b:int64;var x,y:int64):int64;
    var   
        t                                   :int64;
    begin
        if (b=0) then
        begin
            x:=1;y:=0;
            exit(a);
        end;
        ex_gcd:=ex_gcd(b,a mod b,x,y);
        t:=x;
        x:=y;
        y:=t-(a div b)*y;
    end;
      
    function gcd(a,p:int64):int64;
    var   
        x, y                                :int64;
          
    begin
        x:=0;y:=0;
        ex_gcd(a,p,x,y);
        x:=(x mod p+p)mod p;
        exit(x);
    end;
      
    function mi(x,y,q:int64):int64;
    var
        rec                                 :int64;
          
    begin
        rec:=1;
        while (y>0) do
        begin
            if y and 1=1 then rec:=rec*x mod q;
            x:=x*x mod q;
            y:=y shr 1;
        end;
        exit(rec);
    end;
      
    function fac(n,p,q:int64):int64;
    var
        cnt                                 :int64;
        i                                   :longint;
    begin
        cnt:=1;
        for i:=1 to n do
            if (i mod p>0) then
                cnt:=cnt*i mod q;
        exit(cnt);
    end;
      
    function fact(n:int64;var sum:int64;p,q:int64):int64;
    var
        cnt, rec                            :int64;
          
    begin
        rec:=1;
        cnt:=fac(q,p,q);
        while n>=p do
        begin
            sum:=sum+n div p;
            if (n div q>0) then rec:=rec*(mi(cnt,n div q,q) mod q)mod q;
            if (n mod q>0) then rec:=rec*(fac(n mod q,p,q)mod q) mod q;
            n:=n div p;
        end;
        if n>1 then rec:=rec*fac(n,p,q) mod q;
        exit(rec);
    end;
      
    function combine(n,m,p,q:int64):int64;
    var   
        ans1, ans2, ans3, ans               :int64;
        a, b, c                             :int64;
          
    begin
        a:=0;b:=0;c:=0;
        ans1:=fact(n,a,p,q);
        ans2:=fact(m,b,p,q);
        ans3:=fact(n-m,c,p,q);
        a:=a-(b+c);
        ans:=mi(p,a,q);
        ans:=ans*ans1 mod q;
        ans:=ans*gcd(ans2,q) mod q;
        ans:=ans*gcd(ans3,q) mod q;
        exit(ans);
    end;
      
    function doit(n,m:longint):int64;
    var
        i                                   :longint;
        x, y, sum                           :int64;
              
    begin
        sum:=0;
        for i:=1 to tot do
                a[i]:=combine(n,m,pj[i],pi[i]);
        for i:=1 to tot do
        begin
            x:=0;y:=0;
            ex_gcd(s[i],pi[i],x,y);
            x:=(x mod pi[i]+pi[i])mod pi[i];
            sum:=(sum+((x*s[i] mod p)*a[i])mod p)mod p;
        end;
        exit(sum mod p);
    end;
      
    procedure main;
    var   
        i                                   :longint;
        w                                   :array[0..100] of longint;
        ans                                 :int64;
        sum                                 :int64;
          
    begin
        readln(p);
        divide(p);
        for i:=1 to tot do s[i]:=p div pi[i];
        readln(n,m);
        sum:=0;
        for i:=1 to m do
        begin
            readln(w[i]);
            inc(sum,w[i]);
        end;
        if sum>n then
        begin
            writeln('Impossible');
            exit;
        end;
        ans:=1;
        for i:=1 to m do
        begin
            ans:=ans*doit(n,w[i]) mod p;
            n:=n-w[i];
        end;
        writeln(ans);
    end;
      
    begin
        main;
    end.
  • 相关阅读:
    SQL Server 2008通过PassPhrase加密数据
    SQL Server 2008之Values
    Merge(在一条语句中使用Insert,Update,Delete) 对两个表进行同步数据
    Linux yum常用命令介绍
    SQL Server 2008之WaitFor
    Android之TelephonyManager类的方法详解
    TextView里的文 html
    adb
    Apk得到Java源代码
    【Android】调用系统应用常用uri & intent设置
  • 原文地址:https://www.cnblogs.com/BLADEVIL/p/3485794.html
Copyright © 2011-2022 走看看