题目大意:
小A得到了一个数列A,他告诉你这个数列中所有的A[i]都是1到n的自然数,并且告诉你对于一些A[i]不能取哪些值。无聊的你想要知道所有可能的数列的积的和。定义一个数列的积为这个数列所有数的乘机。由于答案太大,只要模10^9+7输出即可。
对于前30%的数据,n<=4,m<=10,k<=10
另有20%的数据k=0
对于70%的数据n<=1000,m<=1000,k<=1000
对于100%的数据,n<=10^9,m<=10^9,k<=10^5,1<=y<=n,1<=x<=m
题解:
快速幂+枚举:
我们找规律发现,
设到当前第i点乘积和的为sum[i],则到i+1个点,可以* 1,* 2,…… (n-1),*n
则sum[i]:=sum[i-1]*(1+2+……+n)
然后我们先用公式求出1~n的sum
则sum=(1+n)*n/2,2必定被整除
然后对于K个限制,我们排序以后,去重另外做,然后将剩下没变的M-X位,X是K个限制改变了的点的总数。
然后求 sum^(m-x)*对这X位的处理。
前者可以用快速幂求,后者直接暴力。
然后注意过程中的取模。
const
modn=1000000007;
var
c:array [0..100001,1..2] of longint;
n,m,k,i,j,p:longint;
ans,q,l:int64;
function qm(t:int64):int64;
begin
exit(t mod modn);
end;
function ksm(a,b:int64):int64;
begin
ksm:=1;
while b<>0 do
begin
if b mod 2=1 then
ksm:=qm(ksm*a);
b:=b div 2;
a:=qm(a*a);
end;
end;
procedure qsort(l,r:longint);
var
i,j,mid,kid:longint;
begin
if l>=r then exit;
mid:=c[(l+r) div 2,1];
kid:=c[(l+r) div 2,2];
i:=l; j:=r;
repeat
while (c[i,1]<mid) or ((c[i,1]=mid) and (c[i,2]<kid)) do inc(i);
while (c[j,1]>mid) or ((c[j,1]=mid) and (c[j,2]>kid)) do dec(j);
if i<=j then
begin
c[0]:=c[i];c[i]:=c[j];c[j]:=c[0];
inc(i); dec(j);
end;
until i>j;
qsort(i,r);
qsort(l,j);
end;
begin
readln(n,m,k);
if (k>=n) and (k>=m) then
if k>=n*m
then begin
writeln(0);
halt;
end;
l:=qm(qm(qm(n+1)*n) div 2);
ans:=1;
for i:=1 to k do readln(c[i,1],c[i,2]);
qsort(1,k);
i:=1;
while i<=k do
begin
dec(m);
j:=1;
while c[i,1]=c[i+j,1] do inc(j);
q:=qm(l-c[i,2]+modn); j:=j-1;
for p:=i+1 to i+j do
if c[p,2]<>c[p-1,2] then q:=qm(q-c[p,2]+modn);
ans:=qm(ans*q);
i:=i+j+1;
end;
ans:=qm(ans*ksm(l,m));
writeln(ans);
end.