Describe
為了使得大家高興,小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
Explain
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
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
Solution
首先我們想一下如果沒有限制那麼最後的結果是多少.對於數列中的每一項,我們都可以取1~n,共有m項,最後總結果其實挺整齊的,$(1+2+3+......+n) * (1+2+3+......n) *...... *(1+2+3+......n) $共乘m次,因為每個數都可以從每乘一次的數(1 ~ n)中選一個算出數列的積,最後相加,化簡 \((1+2+3+4+......+n)^m\) ,也就是\(((1+n)*n/2)^m\) .可以看做用了分步乘法原理,共有m次方,也就是每個數對結果的貢獻.
如果一個數被限制了,那麼這個數所在的某一次方中就不是1 ~ n的加和了,要減去被限制的數,沒有被限制的數還是1 ~ n加和,最後m個數遍歷完,將m個得到的結果乘起來,就是最後結果了.
Attention
資料範圍如此之大,快速冪!!!
注意取模,只要對結果沒影響就取模.
去重邊,樣例中就有
Code
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
#include <iostream>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
const ll Mod=1000000007;
map<pair<ll,ll>,ll> ma1;
map<ll,ll> ma2;
ll hj[maxn],n,m,k,js;
ll cf(ll now,ll zs){
ll jl=now%Mod,ans=1;
while(zs){
if(zs&1)ans=(ans*(jl%Mod))%Mod;
jl=(jl*(jl%Mod))%Mod;
zs>>=1;
}
return ans;
}
int main(){
scanf("%lld%lld%lld",&n,&m,&k);
for(ll i=1;i<=k;++i){
ll x,y;
scanf("%lld%lld",&x,&y);
if(!ma2[x]) hj[++js]=x;
if(ma1[make_pair(x,y)])continue;
ma1[make_pair(x,y)]=1;
ma2[x]+=y;
}
ll ans=1,cj=(n+1)*n/2;
for(ll i=1;i<=js;++i)
ans=(ans*((cj-ma2[hj[i]])%Mod))%Mod;
printf("%lld\n",(ans%Mod)*(cf(cj,m-js)%Mod)%Mod);
return 0;
}
hzoi