[bzoj2751]: [HAOI2012]容易题(easy)(快速幂)

来源:互联网 发布:空间如何绑定域名 编辑:程序博客网 时间:2024/05/14 10:37

2751: [HAOI2012]容易题(easy)

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 2208  Solved: 931
[Submit][Status][Discuss]

Description


为了使得大家高兴,小Q特意出个自认为的简单题(easy)来满足大家,这道简单题是描述如下:
有一个数列A已知对于所有的A[i]都是1~n的自然数,并且知道对于一些A[i]不能取哪些值,我们定义一个数列的积为该数列所有元素的乘积,要求你求出所有可能的数列的积的和 mod 1000000007的值,是不是很简单呢?呵呵!

Input


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

Output

一行一个整数表示所有可能的数列的积的和对1000000007取模后的结果。如果一个合法的数列都没有,答案输出0。

Sample Input

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

Sample Output

90
样例解释
A[1]不能取1
A[2]不能去2、3
A[4]不能取3
所以可能的数列有以下12种
数列 积
2 1 1 1 2
2 1 1 2 4
2 1 2 1 4
2 1 2 2 8
2 1 3 1 6
2 1 3 2 12
3 1 1 1 3
3 1 1 2 6
3 1 2 1 6
3 1 2 2 12
3 1 3 1 9
3 1 3 2 18

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

Source


题解

虽然这个题目就叫容易题而且所有题解都说这个很水

但对于我这个刚学的蒟蒻 还是好难啊啊啊啊大哭

于是乎又去看题解 

不过 好歹看懂了 首先 没有限制的话 答案是sum^m(sum=1到n的和)

那么 引用一下http://blog.csdn.net/jr_mz/article/details/48661767 


题意:有一个数列共有m项,其中每一项的值都是不大于n的正整数,并且给出k个形如第i项不能为j的约束。求出所有可能的数列的各项之积之和对1,000,000,007取模的结果。

例如n=2,m=2,约束第1项不能填1,则数列可以是2,1或2,2,每个数列的各项之积依次为2和4,则答案为2+4=6。n,m<=1,000,000,000,k<=1

这里不可能把所有情况都枚举一次,毕竟可能的数列的数量还是指数级别的。

应该注意到答案也等于各项可取的数之和之积,如在上面的例子中,第1项可取2和为2,第2项可取1或2和为3,则答案为2*3=6。

由于k远小于n,因此只要统计出某些项不能取哪些数,用总和相减就能得到能取的数之和。统计任务可以用快排和哈希完成,还要注意给约束判重。

又因为k也远小于m,实际上绝大部分项是没有约束的,所以即能取的数之和都是总和,由于m很大,因此可以用快速幂来解决。


上面的话中红字就是这题的关键了 算法就是先把有约束的乘起来 然后在把没有约束的乘起来


对于没有约束的 如果有tot个 那么这个乘起来就是sum^tot 这个是要用到快速幂来计算的


还有 排序的目的是为了去重


//参考:http://blog.csdn.net/jr_mz/article/details/48661767 #include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<cmath>#define ll long long#define mod 1000000007using namespace std;int m,n,k;ll ans;struct node{int pos,val;}a[100005];bool cmp(node a,node b){if(a.pos==b.pos) return a.val<b.val;return a.pos<b.pos;}ll quick_pow(ll a,ll b,ll c){ll ans=1;for(ll i=b;i;i>>=1,a=(a*a)%c)if(i&1) ans=(ans*a)%c;return ans;}int main(){scanf("%d%d%d",&n,&m,&k);for(int i=1;i<=k;i++){scanf("%d%d",&a[i].pos,&a[i].val);}sort(a+1,a+1+k,cmp);int tot=m;ans=1;ll sum=(ll)n*(n+1)/2%mod;ll tmp=sum;//积的和 = 每一位分开 算出能取到的值的和 最后乘起来 for(int i=1;i<=k;i++){if(a[i].pos!=a[i-1].pos&&i!=1){ans=ans*tmp%mod;tmp=sum;tot--;}if(a[i].pos!=a[i-1].pos||a[i].val!=a[i-1].val){tmp-=a[i].val;if(tmp<0) tmp+=mod;}}tot--;ans=ans*tmp%mod;//最后一个还没算printf("%lld\n",ans*quick_pow(sum,tot,mod)%mod);//没限制的有tot个 每个的和是sum return 0;}




原创粉丝点击