首先,原題題目就叫這個,不是我諷刺這個題簡單……
原題地址c++
我們先假設我一個限制都沒有,那麼每一個數均可以取\(1~n\)之間的任何一個整數,在本身的腦海裏提一遍公因數就會發現這時答案爲\((1+2+ \dots +n)^m\),再用上求和公式變爲\((\frac{n(n+1)}{2})^m\)。
那麼如今咱們加上限制條件,每加上一個限制就少一個選擇,那麼咱們就把這個限制數從這個乘數裏剔除便可,即原來是\(1+2+ \dots +n\),如今變爲\(1+2+ \dots +n-limit1-limit2 \dots\),也就是\((\frac{n(n+1)}{2})^m-limit1-limit2 \dots\)。而沒有受到限制的數照乘不誤,即如有\(js\)個有限制的數那麼這些沒限制的數乘起來就是\((\frac{n(n+1)}{2})^{m-js}\)。最後結果把有限制的沒限制的乘一塊兒便可。
幾點提醒:
1.數太大了,能取模的地方都取模。
2.用快速冪優化。
3.樣例就能看出來可能有重複限制,記得去重。優化
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1000000007; const int maxn=1e5+3; map<pair<ll,ll>,bool> inf; map<ll,ll> sum; ll n,m,k,js,num[maxn]; ll power(ll a,ll x){ a%=mod; ll ans=1; for(;x;x>>=1,a=a*a%mod){ if(x&1) ans=ans*a%mod; } return ans%mod; } ll read(){ ll s=0,w=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar(); return s*w; } int main(){ n=read(); m=read(); k=read(); while(k--){ ll x,y; x=read(); y=read(); if(!sum[x]) num[++js]=x; if(inf[make_pair(x,y)]) continue; inf[make_pair(x,y)]=1; sum[x]+=y; } ll ans=1,Max=(n+1)*n/2; for(ll i=1;i<=js;i++){ ans*=(Max-sum[num[i]])%mod; ans%=mod; } printf("%lld",ans%mod*power(Max,m-js)%mod%mod); return 0; }
幸甚至哉,歌以詠志。spa