求组合数+取模,详解

来源:互联网 发布:吉林广电网络集团 编辑:程序博客网 时间:2024/06/05 20:07

题目大意:
在M里面取出N个数,求有多少种组合方式。
结果对23333取模。

1<=n,m<=10000

题解:
组合数
看数据就发现可以直接用杨辉三角形或者组合数公式做,应该不会超时。

1.杨辉三角形:
时间复杂度:O(M^2)

var    n,m,i,j:longint;  f:array[0..1,-1..10001] of longint;begin  assign(input,'d.in');  assign(output,'d.out');  reset(input);  rewrite(output);  readln(n,m);  f[0,0]:=1;  for i:=1 to m do    for j:=0 to i do      f[i mod 2,j]:=(f[(i+1) mod 2,j]+f[(i+1) mod 2,j-1]) mod 23333;  write(f[m mod 2,n]);  close(input);  close(output);end.

2、公式法做:
这里写图片描述
这里写图片描述
然后注意取模。

PS:
对于组合数公式有一个优化,
设a/b mod c=a/b * 1 mod c,然后我们假设 b*x mod c=1,这时候我们说满足这种情况的x为b的逆元,这时候a/b * 1 mod c=a/b * b*x mod c,就可以约掉b,结果为a*x mod c。
这时候组合数的中的除法,就可以转化成乘法,即
C(N,M)=n!/m!(n-m)! mod c转化成
N!* x[m!] * x[(n-m)!] mod c。
对于一个模数p,若p为素数,则
x[i!]=i!^(p-2)
时间复杂度:O(Nlog₂N)

const    modn=23333;var    f:array [0..1] of longint;    ny:array [0..10001] of longint;    i,n,m:longint;function gcd(a,b:longint):longint;begin    gcd:=1;    while b<>0 do    begin        if b mod 2=1 then           gcd:=gcd*a mod modn;        b:=b div 2;        a:=a*a mod modn;    end;end;begin    assign(input,'d.in');  reset(input);    assign(output,'d.out');rewrite(output);    readln(m,n);    f[0]:=1;    ny[0]:=1;    for i:=1 to n do        begin              f[i mod 2]:=f[(i+1) mod 2]*i mod modn;              ny[i]:=gcd(f[i mod 2],modn-2);        end;    writeln(f[n mod 2]*ny[m] mod modn*ny[n-m] mod modn);    close(input); close(output);end.
原创粉丝点击