luogu P4593 [TJOI2018]教科书般的亵渎

这是个求自然数幂和的模板题。难点在于理解题意。

很容易发现 (k=m+1),然后就是 (O(k^2)) 的累计答案。

加上插值求自然数幂和,总复杂度为 (O(k^3))

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define int long long

using namespace std;

typedef long long LL;
const int N=60,M=1000000007,K=1000000;
int m,A[K+9],p[K],cnt,d[K+9];
LL n,a[N],k,pre[K],suf[K],fac[K],inv_fac[K];

int ksm(int a,int b)
{
	int res=1;
	while(b)
	{
		if(b&1)
			res=1ll*res*a%M;
		b>>=1,a=1ll*a*a%M;
	}
	return res;
}

void prework(int k)
{
	d[1]=1,cnt=0;
	for (int i=2;i<=k+2;i++)
		A[i]=0; 
	for (int i=2;i<=k+2;i++)
	{
		if(!A[i])
			A[i]=i,p[++cnt]=i,d[i]=ksm(i,k);
		for (int j=1;j<=cnt;j++)
		{
			if(p[j]>A[i]||p[j]>(k+2)/i)
				break;
			A[p[j]*i]=p[j];
			d[p[j]*i]=1ll*d[p[j]]*d[i]%M;
		}
	}
//	printf("%d
",k+2);
//	for (int i=1;i<=k+2;i++)
//		printf("%d ",d[i]);puts("");
	for (int i=2;i<=k+2;i++)
		d[i]=(d[i]+d[i-1])%M;
}

void init()
{
	scanf("%lld %lld",&n,&m);
	for (int i=1;i<=m;i++)
		scanf("%lld",&a[i]);
	sort(a+1,a+1+m);
	k=m+1;
}

int Get_Sum(LL n,int k)
{
	prework(k);
	pre[0]=1;
	for (int i=1;i<=k+2;i++)
		pre[i]=1ll*pre[i-1]*((n-i)%M)%M;
	suf[k+3]=1;
	for (int i=k+2;i>=1;i--)
		suf[i]=1ll*suf[i+1]*((n-i)%M)%M;
	fac[0]=1;
	for (int i=1;i<=k+2;i++)
		fac[i]=1ll*fac[i-1]*i%M;
	inv_fac[k+2]=ksm(fac[k+2],M-2);
	for (int i=k+1;i>=0;i--)
		inv_fac[i]=1ll*inv_fac[i+1]*(i+1)%M;
	int ans=0;
	for (int i=1;i<=k+2;i++)
		ans=(ans+d[i]*pre[i-1]%M*suf[i+1]%M*inv_fac[i-1]%M*inv_fac[k+2-i]%M*(k+2-i&1?-1:1))%M;
	return ans;
}

void work()
{
	LL ans=0;
	a[++m]=n+1;
	for (int i=0;i<=m;i++)
		for (int j=i+1;j<=m;j++)
			ans=(ans+(Get_Sum(a[j]-1-a[i],k)-Get_Sum(a[j-1]-a[i],k))%M)%M;
	printf("%lld
",(ans+M)%M);
}

signed main()
{
	int T;
	scanf("%lld",&T);
	while(T--)
	{
		init();
		work();
	}
	return 0;
}
原文地址:https://www.cnblogs.com/With-penguin/p/13460580.html