[HAOI2012] 容易题

题目

首先,原题题目就叫这个,不是我讽刺这个题简单……
原题地址

解说

咱们先假设我一个限制都没有,那么每个数都可以取(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