//引入样式文件(页首)

[TJOI2018]教科书般的亵渎

首先,认真读题不难发现若血量的区间 \([1,m_i]\) 连续,则只需要一张亵渎就可以杀死区间 \([1,m_i]\) 内所有怪物,所以 \(k = m+1\)

考虑到这点,我们就可以轻松的写出式子(保证 \(a_i\) 升序):

定义 \(a_0 = 0\),有

\[\Large Ans = \sum\limits_{i=1}^{m+1}\left(\sum\limits_{j=1}^{n-a_{i-1}}j^{m+1}-\sum\limits_{j=i}^m(a_j-a_{i-1})^{m+1}\right) \]

写出了这个式子,如果你知识面不足的话,就没有然后了(至少像我这种蒟蒻是这样的)。

只需知道 \(\sum\limits_{j=1}^{n-a_{i-1}}j^{m+1}\) 是一个 \(m+2\) 次的多项式,这个式子就可以算了。

\(\sum\limits_{i=1}^{x}i^n\)\(n+1\) 次多项式好像是一个比较常用的结论,但我本人并没有找到网络上的证明,所以尝试着自己证了一下。

大量公式警告

证明: \(\sum\limits_{i=1}^{x}i^n\) 是一个 \(n+1\) 次多项式.

定义:

\[f(x) = \sum\limits_{i=1}^{x}i^n \]

不失一般性,直接考虑 \(n\) 的情况。

\(g(x) = x^{n+1}\)

对每一项 \(g(x)\) 使用二项式定理展开:

\[\begin{aligned} &g(x)=(x-1)^{n+1}+\tbinom{n+1}{1}(x-1)^n\cdots+\tbinom{n+1}{n}(x-1)+\tbinom{n+1}{n+1}\\ &g(x-1)=(x-2)^{n+1}+\tbinom{n+1}{1}(x-2)^n\cdots+\tbinom{n+1}{n}(x-2)+\tbinom{n+1}{n+1}\\ &\cdots\cdots\\ &g(1) = 1^{n+1} \end{aligned}\]

将上述式子全部合并起来有:

\[\sum\limits_{i=1}^x{(x-i+1)^{n+1}}=\sum\limits_{i=1}^{x}\sum\limits_{j=0}^{n+1}\tbinom{n+1}{j}(x-i)^{n-j+1} \]

化简有:

\[x^{n+1} = \sum\limits_{i=1}^{x}\sum\limits_{j=1}^{n+1}\tbinom{n+1}{j}(x-i)^{n-j+1} \]

移项有:

\[x^{n+1} = \sum\limits_{i=1}^{x}\sum\limits_{j=2}^{n+1}\tbinom{n+1}{j}(x-i)^{n-j+1}+\sum\limits_{i=1}^{x}\tbinom{n+1}{1}(x-i)^{n} \]

\[\sum\limits_{i=1}^{x}(x-i)^n = \frac{x^{n+1}-\sum\limits_{i=1}^{x}\sum\limits_{j=2}^{n+1}\tbinom{n+1}{j}(x-i)^{n-j+1}}{n+1} \]

即为:

\[f(x-1)=\sum\limits_{i=1}^{x-1}i^n = \frac{x^{n+1}-\sum\limits_{i=1}^{x}\sum\limits_{j=2}^{n+1}\tbinom{n+1}{j}(x-i)^{n-j+1}}{n+1}-1 \]

这个式子是一个最高项为 \(x^{n+1}\) 次多项式,即猜测成立。

综上,\(f(x) = \sum\limits_{i=1}^{x}i^n\) 是一个 \(n+1\) 次多项式。

回到原式:

\[\Large Ans = \sum\limits_{i=1}^{m+1}\left(\sum\limits_{j=1}^{n-a_{i-1}}j^{m+1}-\sum\limits_{j=i}^m(a_j-a_{i-1})^{m+1}\right) \]

\(\sum\limits_{j=1}^{n-a_{i-1}}j^{m+1}\) 是一个 \(m+2\) 次的多项式所以可以用拉格朗日插值法算出来。

拉格朗日插值的式子:

\[\ell_i(k)=\prod\limits_{i\neq j,i=0}^{n}\frac{k-x_j}{x_i-x_j} \]

\[f(k) = L(k)= \sum\limits_{i=0}^{n}y_i\ell_i(k) \]

这样做是 \(\mathcal{O}(m^2)\),因为本题取值是连续的,所以可以优化到 \(\mathcal{O}(m)\)

优化后的式子长这样:

\[f(k) = \sum\limits_{i=0}^{n-i}(-1)^{i+1}y_i\frac{Pre_{i-1}\cdot Suf_{i+1}}{fac_{i-1}\cdot fac_{n-i}} \]

\(Pre_i\),\(Suf_i\),\(fac_i\) 分别是预处理出来的前缀积,后缀积,阶乘。

对于原式的 \(\sum\limits_{j=i}^m(a_j-a_{i-1})^{m+1}\) 直接暴力算就可以了。

最终的时间复杂度是 \(\mathcal{O}(m^2)\) 的。

Code:

# include <map>
# include <ctime>
# include <cmath>
# include <cstdio>
# include <cstdlib>
# include <cstring>
# include <algorithm>
# define LL long long
# define reg register
const LL mod = 1e9+7;

int T;
LL a[55],n,m,k,Fac[55],Pre[55],Suf[55],f[55],ans;

inline int Mod(const int x){return x < mod ? x : x-mod;}

inline int qpow(LL x,int p=1e9+5)
{
    reg LL res = 1;
    for(; p ; p>>=1,x = (x*x)%mod) if(p&1) res = res*x%mod;
    return res; 
}

inline int Lagrange(const int x)
{
    if(x <= k) return f[x];
    reg LL res = 0;Suf[k+1] = 1;
    for(reg int i = 1; i <= k ; ++i) Pre[i] = Pre[i-1]*(x-i)%mod;
    for(reg int i = k; i >= 1 ; --i) Suf[i] = Suf[i+1]*(x-i)%mod;
    for(reg int i = 1; i <= k ; ++i) 
    res = (res + ((((k-i)&1) ? -1LL : 1LL) * (Pre[i-1]*Suf[i+1]%mod * qpow(Fac[i-1]*Fac[k-i]%mod))%mod * f[i])%mod)%mod;
	return Mod(res+mod);
}

int main()
{
    Fac[0] = Pre[0] = f[1] = 1;
    for(reg int i = 1; i <= 54 ; ++i) Fac[i] = Fac[i-1]*i%mod;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);k = m+3;
        for(reg int i = 1; i <= m ; ++i) scanf("%d",a+i);
        std::sort(a+1,a+m+1);
        while(a[m] == n){m--;n--;k--;}
        for(reg int i = 2; i <= k ; ++i) f[i] = (f[i-1]+qpow(i,m+1))%mod;
        for(reg int i = 1; i <= m+1 ; ++i)
        {
            ans = Mod(ans+Lagrange(n-a[i-1]));
            int aiaj = 0;
            for(reg int j = i; j <= m; ++j) aiaj = Mod(aiaj+qpow(a[j]-a[i-1],m+1));
            ans = Mod(Mod(ans+mod-aiaj)+mod);
        }
        printf("%d\n",ans);ans = 0;
    }
    return 0;
}

\(\mathcal{O}(m^2)\)

posted @ 2020-09-05 11:45  云岁月书  阅读(125)  评论(0)    收藏  举报

载入天数...载入时分秒...