洛谷 P4593 [TJOI2018]教科书般的亵渎(拉格朗日差值法)

传送门


解题思路

首先显然的规律是需要m+1张亵渎。
分别在开始和m个空位处释放(可以想象为整个数组往左移)。
对于每一次释放,根据容斥原理,用总的减去空位置的,可列得式子:

\[\sum_{i=1}^{m+1}(\sum_{j=1}^{n-a[i]}j^{m+1}-\sum_{j=i}^{m}(a[j]-a[i-1]^{m+1})) \]

然后第一个括号里的式子可以用拉格朗日插值法O(mlogm)求解。
所以总复杂度O(Tmlogm)。

AC代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<algorithm>
using namespace std;
const int mod=1e9+7;
int t,m;
long long n,a[55];
long long fenzi=1,res,ans;
long long fenmu1[55],fenmu2[55];
long long qp(long long a,long long b){
	if(b==0) return 1;
	if(b==1) return a;
	long long ans=qp(a,b/2);
	if(b&1) return ans*ans%mod*a%mod;
	return ans*ans%mod;
} 
inline long long getinv(long long a){
	return qp(a,mod-2);
}
long long lglr(int n,int k){
	res=ans=0,fenzi=1;
	if(k+2>=n){
		for(int i=1;i<=n;i++) ans=(ans+qp(i,k))%mod;
		return ans;
	}
	fenmu1[1]=fenmu2[k+2]=1;
	for(int i=1;i<=k+2;i++){
		fenzi=fenzi*(n-i)%mod;
		fenmu1[i+1]=fenmu1[i]*i%mod;
	}
	for(int i=k+1;i>=1;i--){
		fenmu2[i]=fenmu2[i+1]*(i-k-2)%mod;
	}
	for(int i=1;i<=k+2;i++){
		res=(res+qp(i,k))%mod;
		ans=(ans+res*fenzi%mod*getinv(n-i)%mod*getinv(fenmu1[i]*fenmu2[i]%mod)%mod)%mod;
	}
	return (ans+mod)%mod;
}
int main(){
	cin>>t;
	while(t--){
		long long ans=0;
		cin>>n>>m;
		for(int i=1;i<=m;i++) cin>>a[i];
		sort(a+1,a+m+1);
		for(int i=1;i<=m+1;i++){
			ans=(ans+lglr(n-a[i-1],m+1))%mod;
			for(int j=i;j<=m;j++){
				ans=(ans-qp(a[j]-a[i-1],m+1))%mod;
			}
		}
		cout<<(ans%mod+mod)%mod<<endl;
	}
    return 0;
}
posted @ 2021-05-30 21:49  尹昱钦  阅读(77)  评论(0编辑  收藏  举报