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

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] <script type="math/tex" id="MathJax-Element-1">*</script>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.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在华为布道者1721年的问题中,提到了一个关于2023年9的问题,问题是关于二级t1的部分逆序重放。 首先,二级数是指数中每个元素仍然是一个数的数。而t1则指的是第一个层级的数。 那么,问题就是在2023年9,对于一个二级t1,需要进行部分逆序重放的操作。 部分逆序重放是指,对数中的一部分元素进行逆序重排,而不改变其他元素的顺序。 具体的操作步骤如下: 1. 确定需要逆序重放的部分。在二级t1中,我们需要确定要逆序重放的子数的起始位置和结束位置。 2. 计算子数的长度。通过起始位置和结束位置的索引差来确定这个长度。 3. 对子数进行逆序重排。可以使用循环或者递归的方法来反转子数中的元素。 4. 将逆序重排后的子数放回原来的位置。根据起始位置和结束位置,将逆序重排后的子数的元素放回原数中。 通过以上步骤,就可以实现对二级t1的部分逆序重放操作。 需要注意的是,在2023年9进行这个操作时,要注意数的索引范围以及边界条件,以避免数越界等错误。 总结起来,1721年的问题所提到的是在2023年9对二级t1进行部分逆序重放的操作。通过确定部分逆序重放的起始位置和结束位置,计算子数的长度,对子数进行逆序重排,再将重排后的子数放回原数中,就可以完成这个操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值