[TJOI2018]教科书般的亵渎题解

[TJOI2018]教科书般的亵渎

洛谷题目链接


题目大意

\(1...n\)个血量的怪物,\(n\)如题面所示,其中缺失了\(m\)种血量的怪物,如果我们用一次亵渎,那么会给所有怪物扣一滴血,每一次用亵渎每只怪物会获得\(x^k\)的分数,注意\(x\)是这次亵渎造成的伤害前的血量。另外每次如果有用亵渎有怪物死亡,就会自动释放一次亵渎,不计分数。

\(m=0\)时,一张亵渎就可以杀死所有怪物,所以分数为\(\sum_{i=1}^ni\)

\(m=1\)时,需要两张亵渎,第一次的分数\(\sum_{i=1}^ni^2-a^2\),缺失血量为\(a\)的怪物不计入分数所以减去\(a^2\),第二次的分数为\(\sum_{i=1}^{n-a}i^2\)因为少于\(a\)的怪物都已经死了,大于\(a\)的怪物血量变成了\(1...n-a\)

先考虑需要几张亵渎,如果每只缺少血量的怪物是不连续的,即连续缺少的数量只为\(1\)个,这时候很好理解,需要\(m+1\)个,如果是连续的,也一样,因为假设连续的\(m\)个,需要\(m\)张,另外杀死怪物需要\(1\)张所以也是\(m+1\)个。

我们根据这个思路,可得:\(ans=\sum_{i=1}^{m+1}(\sum_{j=1}^{n-a[i-1]}j^{m+1}-\sum_{j=i}^m(a[j]-a[i-1])^{m+1})\)

当然我们可以直接暴力算,但是时间会超,看一眼数据范围,可以看出瓶颈在\(\sum_{j=1}^{n-a[i-1]}j^{m+1}\)这就可以用拉格朗日插值,当然也可以用其他办法。


关于拉格朗日插值问题

首先,如果你展开\(\sum_{j=1}^{n-a[i-1]}j^{m+1}\)​,会发现是一个\(m+2\)​次的多项式,我不会展开,洛谷上有一篇题解展开了,有兴趣的可以看看,然后我们又知道\(n\)​个点对最多可以定\(n-1\)​次多项式,所以我们需要\(m+3\)​个点对来进行拉格朗日插值,对于拉格朗日的公式\(\sum_{i=1}^n y_i \prod_{i!=j} \frac{x-x_i}{x_i-x_j}\)所以我们必须要先求出所有\(y_i,i<=m+3\)和所有的\(x_i\)。​


代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=1e9+7;
const int MN=55;
int t,n,m,y[MN],x[MN],a[MN];
inline int qpow(int a,int b){
	int res=1ll;
	while(b){
		if(b&1)res=res*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return res;
}
inline int inv(int k){return qpow(k,mod-2);}
inline int large(int k){
	if(k<=m+3)return y[k];
	int res=0ll;
	for(int i=1;i<=m+3;++i){
		int son=y[i]%mod;
		int mom=1ll;
		for(int j=1;j<=m+3;++j){
			if(i!=j)son=(son*(k-x[j]))%mod,mom=(mom*(x[i]-x[j]))%mod;
		}
		res=(res+son*inv(mom))%mod;
	}
	return (res+mod)%mod;
}
signed main(){
	//freopen("defile.in","r",stdin);
	//freopen("defile.out","w",stdout);
	scanf("%lld",&t);
	y[1]=1,x[1]=1;
	while(t--){
		int ans=0;
		scanf("%lld%lld",&n,&m);
		for(int i=1;i<=m;++i)scanf("%lld",&a[i]);
		sort(a+1,a+1+m);
		while(a[m]==n)m--,n--;
		for(int i=2;i<=m+3;++i)x[i]=i,y[i]=(y[i-1]+qpow(i,m+1))%mod;
		for(int i=1;i<=m+1;++i){
			ans=(ans+large(n-a[i-1]))%mod;
			int xnum=0;
			for(int j=i;j<=m;++j)xnum=(xnum+qpow(a[j]-a[i-1],m+1))%mod;
			ans=(ans-xnum)%mod;
		}
		printf("%lld\n",(ans%mod+mod)%mod);
	}
	return 0;
}
posted @ 2021-09-07 21:40  fanner_rick  阅读(383)  评论(0)    收藏  举报