题目大意:
在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.