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

亵渎终于离开标准了,然而铺场快攻也变少了

给一个大力枚举(无任何性质)+艹出自然数幂和的方法,但是复杂度极限是(O(k^4))的,不过跑的好快233

首先简单数学分析可以得出(k=m+1),因为每多一个空缺就会打断一张亵渎的连击

那么我们考虑对于每个空缺求出答案,发现此时所求答案必定为一段自然数幂和并且减去空缺的数字幂

发现数据范围(mle 50),那么我们直接暴力求出所有连续的段,然后大力枚举这一段开始最低的怪的血量

空缺不妨暴力枚举,区间内的自然数幂和直接差分一下,那么我们只要能快速求出(S(n)=sum_{i=1}^n i^k)即可

这里用了第二类斯特林数的推法,(S(n)=sum_{i=1}^n i^k=sum_{i=0}^n i^k)

[=sum_{i=0}^nsum_{j=0}^k{ _j^k}i^{underline j} ]

[=sum_{j=0}^k{ _j^k}sum_{i=0}^ni^{underline j} ]

[=sum_{j=0}^k{ _j^k}j!sum_{i=0}^n C_i^j ]

用归纳法,得(sum_{i=0}^n C_i^j=C_{n+1}^{j+1}),所以上式

[=sum_{j=0}^k{ _j^k}j!C_{n+1}^{j+1} ]

[=sum_{j=0}^k{ _j^k}frac{(n+1)^{underline{j+1}}}{j+1} ]

所以我们预处理出组合数和第二类斯特林数,这部分就是(O(k^2))计算的

因此总复杂度上界为(O(k^4)),实际在(O(k^3))左右(空缺不连续)

CODE

#include<cstdio>
#include<map>
#include<algorithm>
#define RI register int
#define CI const int&
using namespace std;
typedef long long LL;
const int N=55,mod=1e9+7;
int t,n,m,ans,cnt,pfx[N],s[N][N]; LL a[N],pos[N]; map <LL,int> ts;
inline void inc(int& x,CI y)
{
	if ((x+=y)>=mod) x-=mod;
}
inline void dec(int& x,CI y)
{
	if ((x-=y)<0) x+=mod;
}
inline void Stirling_init(CI n)
{
	s[0][0]=1; for (RI i=1;i<=n;++i) for (RI j=1;j<=i;++j)
	s[i][j]=s[i-1][j-1],inc(s[i][j],1LL*j*s[i-1][j]%mod);
}
inline int quick_pow(int x,int p=mod-2,int mul=1)
{
	for (;p;p>>=1,x=1LL*x*x%mod) if (p&1) mul=1LL*mul*x%mod; return mul;
}
inline int low_fact(const LL& x,CI t,int ret=1)
{
	for (RI i=1;i<=t;++i) ret=1LL*ret*(x-i+1)%mod; return ret;
}
inline int pow_sum(const LL& x,CI k,int ret=0)
{
	for (RI i=1;i<=k;++i) inc(ret,1LL*s[k][i]*low_fact(x+1,i+1)%mod*quick_pow(i+1)%mod); return ret;
}
inline int calc(CI x,const LL& y,CI k)
{
	int ret=pow_sum(y,k); dec(ret,pow_sum(x-1,k)); return ret;
}
inline int none_sum(CI st,const LL& lim,CI k,int ret=0)
{
	for (RI i=1;i<=m;++i) if (a[i]>=lim) inc(ret,quick_pow(st+a[i]-lim,k)); return ret;
}
int main()
{
	for (scanf("%d",&t);t;--t)
	{
		RI i,j; for (ts.clear(),scanf("%d%d",&n,&m),i=1;i<=m;++i) scanf("%lld",&a[i]),ts[a[i]]=1;
		for (sort(a+1,a+m+1),pos[cnt=i=1]=pfx[1]=1;i<=m;++i) if (a[i]!=n)
		if (ts.count(a[i]+1)) ts[a[i]+1]+=ts[a[i]]; else pos[++cnt]=a[i]+1,pfx[cnt]=ts[a[i]];
		for (ans=0,Stirling_init(m+1),i=1;i<=cnt;++i) for (j=1;j<=pfx[i];++j)
		inc(ans,calc(j,j+n-pos[i],m+1)),dec(ans,none_sum(j,pos[i],m+1)); printf("%d
",ans);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/cjjsb/p/10945222.html