2017年8月10日提高组T1 数学

本文介绍了一种求解特定条件下数列所有可能积之和的算法,通过排除指定不可取值并利用快速幂运算来高效计算结果,适用于大规模数据处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

小A得到了一个数列A,他告诉你这个数列中所有的A[i]都是1到n的自然数,并且告诉你对于一些A[i]不能取哪些值。无聊的你想要知道所有可能的数列的积的和。定义一个数列的积为这个数列所有数的乘机。由于答案太大,只要模10^9+7输出即可。

Input

第一行三个整数n,m,k,分别表示数列元素取值范围,数列长度以及限制的数量。
接下来k行每行两个正整数x,y,表示A[x]的值不可能是y。

Output

一行一个整数表示答案。如果连一种可能的数列都没有,就输出0即可。

Sample Input

3 4 5
1 1
1 1
2 2
2 3
4 3

Sample Output

90

Hint

对于前30%的数据,n<=4,m<=10,k<=10
另有20%的数据k=0
对于70%的数据n<=1000,m<=1000,k<=1000
对于100%的数据,n<=109,m<=109,k<=105,1<=y<=n,1<=x<=m

分析:
答案为a[1]a[2]* ……*a[m]
{a[i]为第i位可以选的数的和}

证明一下:
设集合Ai为到k节点时,所有数列的积,这里的积不止一个。设sum[i]为所有的积的和。对于其中一个序列j,有
A[i,j]=A[i-1,j]*1+A[i-1,j]*2+……+A[i-1,j]*n
{除了那些不能选的}

设t为能选的数的和。有A[i,j]=A[i-1,j]*t

对于每个序列都有以上的规律。
有sum[i]=A[i-1,1]*t+A[i-1,2]*t+……+A[i-1,k]*t
{k为序列数,可以不理}

因为 sum[i-1]=A[i-1,1]+A[i-1,2]+……+A[i-1,k]

则sum[i]=sum[i-1]*t

那对于结论,可以先预处理出num为1~n的和,有
num=(1+n)*n/2
我们可以用这个去减那些不能用的,因为不能用的条件只要10^5个。

我们考虑N=10^9, 那至少有10^9-10^5个数和就是num,对于这些数,快速幂即可。

最后排序去重。

代码:

const
 modd=1000000007;
var
 n,m,k,sum,ans,t,p:int64;
 a:array [0..100011,1..2] of longint;
 i,x,y:longint;

procedure qsort(l,r:longint);
  var
    key,temp,key1:int64;
    mid,i,j:longint;
  begin
    if l>=r then exit;
    i:=l;j:=r;
    mid:=(l+r) shr 1;
    key:=a[mid,1];
    key1:=a[mid,2];
    repeat
      while  (a[i,1]<key) or (a[i,1]=key) and (a[i,2]<key1) do inc(i);
      while  (a[j,1]>key) or (a[j,1]=key) and (a[j,2]>key1) do dec(j);
      if i<=j then
      begin
        temp:=a[i,1];a[i,1]:=a[j,1];a[j,1]:=temp;
        temp:=a[i,2];a[i,2]:=a[j,2];a[j,2]:=temp;
        inc(i);dec(j);
      end;
    until i>j;
    qsort(l,j);
    qsort(i,r);
  end;

function power(x,r:int64):int64;
var g:int64;
 begin
  if r=1 then exit(x);
  if r=0 then exit(1);
  g:=power(x,r shr 1);
  g:=g*g mod modd;
  if odd(r) then g:=g*x mod modd;
  exit(g);
 end;

begin
 readln(n,m,k);
 sum:=((n+1)*n div 2) mod modd;
 for i:=1 to k do
   read(a[i,1],a[i,2]);
 qsort(1,k);
 ans:=1; p:=1;
 for i:=1 to k do
  begin
   if a[i,1]<>a[i-1,1] then
    begin
     inc(t);
     ans:=(ans*p) mod modd;
     p:=(sum+modd-a[i,2]) mod modd;
    end
   else
     if a[i,2]<>a[i-1,2] then p:=(p+modd-a[i,2]) mod modd;
  end;
 ans:=(ans*p) mod modd;
 ans:=(ans*power(sum,m-t)) mod modd;
 writeln(ans);
end.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值