问题转化成求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:
    User: BLADEVIL
    Language: Pascal
    Result: Accepted
    Time: ms
    Memory: kb
****************************************************************/
 
//By BLADEVIL
var
    m, n                                :longint;
    pj, c                               :array[..] of longint;
    pi, s, a                            :array[..] of int64;
    p                                   :int64;
    tot                                 :longint;
  
procedure divide(p:int64);
var   
    i, j                                :longint;
      
begin
    tot:=;
    for i:= to trunc(sqrt(p)) do
    if p mod i= then
    begin
        inc(tot);
        pj[tot]:=i;
        while p mod i= do
        begin
                inc(c[tot]);
                p:=p div i;
        end;
    end;
    if p> then
    begin
        inc(tot);
        pj[tot]:=p;
        c[tot]:=;
    end;
    for i:= to tot do
    begin
        pi[i]:=;
        for j:= 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=) then
    begin
        x:=;y:=;
        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:=;y:=;
    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:=;
    while (y>) do
    begin
        if y and = then rec:=rec*x mod q;
        x:=x*x mod q;
        y:=y shr ;
    end;
    exit(rec);
end;
  
function fac(n,p,q:int64):int64;
var
    cnt                                 :int64;
    i                                   :longint;
begin
    cnt:=;
    for i:= to n do
        if (i mod p>) 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:=;
    cnt:=fac(q,p,q);
    while n>=p do
    begin
        sum:=sum+n div p;
        if (n div q>) then rec:=rec*(mi(cnt,n div q,q) mod q)mod q;
        if (n mod q>) then rec:=rec*(fac(n mod q,p,q)mod q) mod q;
        n:=n div p;
    end;
    if n> 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:=;b:=;c:=;
    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:=;
    for i:= to tot do
            a[i]:=combine(n,m,pj[i],pi[i]);
    for i:= to tot do
    begin
        x:=;y:=;
        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[..] of longint;
    ans                                 :int64;
    sum                                 :int64;
      
begin
    readln(p);
    divide(p);
    for i:= to tot do s[i]:=p div pi[i];
    readln(n,m);
    sum:=;
    for i:= to m do
    begin
        readln(w[i]);
        inc(sum,w[i]);
    end;
    if sum>n then
    begin
        writeln('Impossible');
        exit;
    end;
    ans:=;
    for i:= to m do
    begin
        ans:=ans*doit(n,w[i]) mod p;
        n:=n-w[i];
    end;
    writeln(ans);
end;
  
begin
    main;
end.

最新文章

  1. hpunix下11gRac的安装
  2. [异常] openCV安装和配置
  3. c++容器(vector、list、deque)
  4. Java注解(Annotation)自定义注解入门
  5. 微软自带报表rdlc操作(合并同数据项)
  6. A Tour of Go For continued
  7. Ibatis的分页机制的缺陷
  8. postfix日志分析pflogsumm
  9. selenium 执行js,实现滚动条
  10. docker学习(一)
  11. centos7 更新Firefox版本
  12. 学习笔记—XML
  13. LVS实现负载均衡安装配置详解
  14. 002 网上看的unity学习路线
  15. Android开发:在Eclipse中配置Android环境
  16. [C#]实现任何数据库类型的DbHelper帮助类
  17. centos如何查看linux内核,版本号
  18. java指令备忘
  19. poj1321 棋盘问题(DFS)
  20. mysql插入中文出错,提示1366 - Incorrect

热门文章

  1. 怎么防止别人动态在你程序生成代码(怎么防止别人反编译你的app)
  2. jmeter设置全局变量的方法
  3. 问题 A: 完数
  4. git instaweb 500 error
  5. Failed loading D:\Program Files\phpStudy20161103\php\php-5.6.27-nts\ext\php_xdebug.dll
  6. BZOJ 4184 shallot 线性基+分治
  7. Visual Studio 2012,创建工程Build Driver,基于纯Source Code.
  8. CKEditor的基本使用
  9. Metrics+ElasticSearch+grafana
  10. 安装和配置hadoop集群步骤