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

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

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

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

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

发现数据范围\(m\le 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}^n\sum_{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\n",ans);
    }
    return 0;
}
posted @ 2019-05-29 17:40 hl666 阅读(...) 评论(...) 编辑 收藏