博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
bzoj 2142 国家集训队试题 礼物
阅读量:7040 次
发布时间:2019-06-28

本文共 4389 字,大约阅读时间需要 14 分钟。

问题转化成求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 BLADEVILvar    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.

 

转载于:https://www.cnblogs.com/BLADEVIL/p/3485794.html

你可能感兴趣的文章
Racket 6.7最新版本:提供对Android App的支持及改进的REPL等等
查看>>
Eclipse发布MicroProfile 1.4和2.0
查看>>
Kubernetes日志分析利器:Elassandra部署使用指南
查看>>
TOP 13大最热开源微服务Java框架
查看>>
Swift 3来了!
查看>>
京东构建了全球最大的Kubernetes集群,没有之一
查看>>
Node项目之需求收集平台(一)- 基本介绍
查看>>
ArchSummit北京2015 | “新人”的技术约战
查看>>
Microsoft宣布正式发布Linux on ASE
查看>>
Elm提供的语言级响应性
查看>>
微服务通信策略
查看>>
InfoQ 趋势报告:技术文化\u0026方法2019年实践状况
查看>>
Entity Framework Core 2.0的槽点
查看>>
甲骨文解散Java Mission Control团队事件新进展
查看>>
书评:实战Apache JMeter
查看>>
2014年基于Raspberry Pi的5大项目
查看>>
[deviceone开发]-openPage的动画效果示例
查看>>
EAGLEPCB7.7 gerber文件导出
查看>>
苏宁11.11:苏宁易购移动端的架构优化实践
查看>>
GitHub推出Scientist,帮助开发者重构关键路径代码
查看>>