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.
  • 相关阅读:
    poj 1743 Musical Theme 后缀数组
    poj 1743 Musical Theme 后缀数组
    cf 432D Prefixes and Suffixes kmp
    cf 432D Prefixes and Suffixes kmp
    hdu Data Structure? 线段树
    关于position和anchorPoint之间的关系
    ios POST 信息
    CALayers的代码示例
    CALayers详解
    ios中得sqlite使用基础
  • 原文地址:https://www.cnblogs.com/BLADEVIL/p/3485794.html
Copyright © 2011-2022 走看看