首先,原题题目就叫这个,不是我讽刺这个题简单……
原题地址
咱们先假设我一个限制都没有,那么每个数都可以取\(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;
}
幸甚至哉,歌以咏志。
原文:https://www.cnblogs.com/DarthVictor/p/12885235.html