BZOJ.3453.tyvj 1858 XLkxc(拉格朗日插值)

BZOJ

题意即求\[\sum_{i=0}^n\sum_{j=1}^{a+id}\sum_{x=1}^jx^k\]

我们知道最后一个\(\sum\)是自然数幂和,设\(f(n)=\sum_{x=1}^nx^k\),这是一个\(k+1\)次多项式,可以插值求出(当然本题只需要求出任意\(k+3\)个值即可不需要插值)。
\(g(n)=\sum_{i=1}^nf(i)\),(打表)差分可知这是一个\(k+2\)次多项式。
同样令\(h(n)=\sum_{i=0}^ng(a+id)\),同样差分可知这是一个\(k+3\)次多项式。
所以用拉格朗日插值我们代入\(k+4\)个值就可以求出\(h(n)\)了。

也就是先求\(k+3\)\(f(x)\)的值,再求出\(k+3\)\(g(x)\)的值,然后对\(g\)插值求\(k+4\)\(g(a+xd)\),前缀和一下就有了\(h\)\(k+4\)个值,然后再插一次就得到\(h(n)\)了。(嵌套好鬼畜...)


注意\(f,g,h\)都是个前缀和...
注意这题两倍的模数会爆int。可以用unsigned int


从这题可以看出:

  1. 多一个\(\sum\)一般会使多项式次数+1。
  2. 插值可以嵌套,且复杂度不变,仍是\(O(k^2)\)

这是伯努利数的做法:https://blog.csdn.net/qq_20669971/article/details/65938763


//824kb 28ms
#include <cstdio>
#include <algorithm>
#define mod 1234567891
#define Mod(x) x>=mod&&(x-=mod)
#define Add(x,v) (x+=v)>=mod&&(x-=mod)
typedef long long LL;
typedef unsigned int uint;
const int N=130;

uint g[N],h[N],ifac[N];

inline uint FP(uint x,uint k)
{
    uint t=1;
    for(; k; k>>=1,x=1ll*x*x%mod)
        if(k&1) t=1ll*t*x%mod;
    return t;
}
uint Lagrange(uint *y,const int m,uint x)
{
    static uint pre[N],suf[N];
    pre[0]=x, suf[m+1]=1;
    for(int i=1; i<m; ++i) pre[i]=1ll*pre[i-1]*(x+mod-i)%mod;
    for(int i=m; i; --i) suf[i]=1ll*suf[i+1]*(x+mod-i)%mod;
    LL ans=0;
    for(int i=0,up,down; i<=m; ++i)
    {
        if(i) up=1ll*pre[i-1]*suf[i+1]%mod*y[i]%mod;
        else up=1ll*suf[i+1]*y[i]%mod;
        down=(m-i)&1?mod-1ll*ifac[i]*ifac[m-i]%mod:1ll*ifac[i]*ifac[m-i]%mod;
        ans+=1ll*up*down%mod;
    }
    return ans%mod;
}

int main()
{
    ifac[N-1]=1119688141;//是129!的逆元不是129的!!!今天错了两次这个真是醉了=-= 
    for(int i=N-1; i; --i) ifac[i-1]=1ll*ifac[i]*i%mod;

    int T,K; uint a,n,d; g[0]=0;
    for(scanf("%d",&T); T--; )
    {
        scanf("%d%u%u%u",&K,&a,&n,&d);
        for(int i=1; i<=K+2; ++i) g[i]=g[i-1]+FP(i,K), Mod(g[i]); //f = \sum i^k
        for(int i=1; i<=K+2; ++i) Add(g[i],g[i-1]); //g = \sum f(i)
        h[0]=Lagrange(g,K+2,a);
        for(int i=1; i<=K+3; ++i) Add(a,d), h[i]=h[i-1]+Lagrange(g,K+2,a), Mod(h[i]);
        printf("%d\n",(int)Lagrange(h,K+3,n));
    }
    return 0;
}

转载于:https://www.cnblogs.com/SovietPower/p/10244452.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值