教科书般的亵渎

link

只可惜我不玩游戏。听说这是炉石传说里的一种术语?不知道,我没玩过,但是它勾起了我五年前的回忆。从某种意义上来说,一个初三下期期末的人已经死去了许许多多,留下的便更为珍贵。

唉。莫名伤感。

说回题目。这是一个拉格朗日插值的应用,主要表现在对于 \(\sum i^k\) 的求值上。其它的后面再说,先分析一下这个东西。上午才推了式子,有:

\[f(m)=\sum\limits_{i=1}^{k+2}s_i\frac{\prod\limits_{j\ne i}(m-j)}{\prod\limits_{j\ne i}(i-j)} \]

(靠打公式真的累。上面那个公式打了一百多个字。)

优化什么的不说了,推过了。接下来着重讲一下这道题和上面那个式子有什么关系。

首先吐槽一下,这道题的题目描述糟糕透顶,而且数据范围似乎给的太小了(朴素拉插应该都能过但没去写)。

首先模拟一下。发现假如一个空位都没有,那么怪兽们就会按照顺序一次死一个,那么最后只会用一张牌;而假如中间有空位,那么怪兽们按顺序死到空位时就找不到合适的怪兽去死了,于是就会停下,然后就会使用下一张亵渎。规律很好找,模拟一下即可。贡献嘛显然可以用整体减空白的方法去处理,空白很少直接暴力,整体部分就可以直接用拉格朗日插值求解即可。

#include<cstdio>
#include<algorithm>
#define zczc
#define int long long
using namespace std;
const int N=60;
const int mod=1e9+7;
inline void read(int &wh){
	wh=0;int f=1;char w=getchar();
	while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
	while(w>='0'&&w<='9'){wh=wh*10+w-'0';w=getchar();}
	wh*=f;return;
}

int m,n,k,a[N],pre[N],suf[N],fac[N];
void enter(){
	read(n);read(m);
	for(int i=1;i<=m;i++)read(a[i]);
	sort(a+1,a+m+1);
	while(a[m]==n)n--,m--;k=m+1;
}
inline int pow(int s1,int s2){
	if(s2==1)return s1;
	if(s2==0)return 1;
	int an=pow(s1,s2>>1);
	if(s2&1)return an*an%mod*s1%mod;
	else return an*an%mod;
}
int work(int wh){
	wh%=mod;
	pre[0]=suf[k+3]=fac[0]=1;
	for(int i=1;i<=k+2;i++)pre[i]=pre[i-1]*(wh-i)%mod;
	for(int i=k+2;i>=0;i--)suf[i]=suf[i+1]*(wh-i)%mod;
	for(int i=1;i<=k+2;i++)fac[i]=fac[i-1]*i%mod;
	int sum=0,ans=0;
	for(int i=1;i<=k+2;i++){
		sum+=pow(i,k);sum%=mod;
		int u=pre[i-1]*suf[i+1]%mod;
		int v=fac[i-1]*fac[k+2-i]*((k-i)%2?-1:1)%mod;
		ans+=sum*u%mod*pow(v,mod-2)%mod;ans%=mod;
	}
	return (ans+mod)%mod;
}
void solve(){
	int ans=0;
	for(int i=1;i<=m;i++){
		ans+=work(n);
		n-=a[i];
		for(int j=i;j<=m;j++){
			ans-=pow(a[j],k);
			if(i^j)a[j]-=a[i];
		}
		ans%=mod;
	}
	ans+=work(n);
	printf("%lld\n",(ans+mod)%mod);
}

signed main(){
	
	#ifdef zczc
	freopen("in.txt","r",stdin);
	#endif
	
	int test;read(test);
	while(test--){
		enter();
		solve();
	}
	
	return 0;
}
posted @ 2022-04-30 15:43  Feyn618  阅读(63)  评论(0编辑  收藏  举报