BZOJ5339: [TJOI2018]教科书般的亵渎

BZOJ5339: [TJOI2018]教科书般的亵渎

https://lydsy.com/JudgeOnline/problem.php?id=5339

分析:

  • 难点在于模拟。
  • 除去模拟的部分,我们需要计算\(\sum\limits_{i=1}^ni^k\)
  • 那这显然是关于\(n\)的一个\(k+2\)次多项式。
  • 暴力高斯消元\(O(k^3)\)即可,每次求值\(O(k)\)
  • 但这题需要计算\(k^2\)次,因此总时间复杂度和多数题解一样,都是\(O(k^3)\)

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
using namespace std;
typedef long long ll;
#define N 60
#define mod 1000000007
ll n,a[N],A[N][N],F[N];
int m,K;
ll qp(ll x,ll y) {
	ll re=1; for(;y;y>>=1,x=x*x%mod) if(y&1) re=re*x%mod; return re;
}
inline void upd(ll &x,ll y) {
	x+=y; if(x>=mod) x-=mod;
}
ll S(ll n) {
	if(n==0) return 0;
	int i;
	n=n%mod;
	ll re=0,now=1;
	for(i=0;i<=K+1;i++) {
		re=(re+now*F[i+1])%mod;
		now=now*n%mod;
	}
	return re;
}
void Gauss(int n) {
	int i,j,k;
	for(i=1;i<=n;i++) {
		for(j=i;j<=n&&!A[j][i];j++) ;
		if(j>n) continue;
		if(i!=j) {
			for(k=i;k<=n+1;k++) swap(A[i][k],A[j][k]);
		}
		ll del=qp(A[i][i],mod-2);
		for(j=i;j<=n+1;j++) A[i][j]=A[i][j]*del%mod;
		for(j=1;j<=n;j++) if(j!=i) {
			del=A[j][i];
			for(k=i;k<=n+1;k++) {
				A[j][k]=(A[j][k]-del*A[i][k])%mod;
			}
		}
	}
}
void solve() {
	memset(A,0,sizeof(A));
	scanf("%lld%d",&n,&m);
	int i,j;
	for(i=1;i<=m;i++) scanf("%lld",&a[i]);
	sort(a+1,a+m+1);
	m=unique(a+1,a+m+1)-a-1;
	for(i=m;i;i--) {
		if(a[i]==n) n--,m--;
		else break;
	}
	ll now,sum;
	K=m+1;
	
	for(i=1;i<=K+2;i++) {
		now=1,sum=0;
		for(j=1;j<=i;j++) sum=(sum+qp(j,K))%mod;
		for(j=1;j<=K+2;j++) {
			A[i][j]=now;
			now=now*i%mod;
		}
		A[i][K+3]=sum;
	}
	Gauss(K+2);
	for(i=1;i<=K+2;i++) F[i]=A[i][K+3];
	
	now=0;
	ll ans=0; a[m+1]=n+1;
	for(i=0;i<=m;i++) {
		for(j=i;j<=m;j++) {
			ans=(ans+S(a[j+1]-1)-S(a[j]))%mod;
		}
		now=a[i+1]-a[i];
		for(j=i+1;j<=m+1;j++) a[j]-=now;
	}
	printf("%lld\n",(ans%mod+mod)%mod);
}
int main() {
	int T;
	scanf("%d",&T);
	while(T--) solve();
}
posted @ 2019-01-06 18:38  fcwww  阅读(237)  评论(0编辑  收藏  举报