【BZOJ 4734】【UOJ 269】【清华集训2016】 如何优雅地求和

12 篇文章 0 订阅
6 篇文章 1 订阅

题意:给定 m 次多项式f(x),求 nk=0f(k)(nk)xk(1x)nk

老年选手石乐志看不出二项式展开的悲惨经历

【搞笑做法】
考虑多项式 f(x)=kakxk 代入原式,将 xk(1x)nk 换成 xnyk ,有

xnjajk(nk)ykkj

gn(m)=k(nk)ykkm ,则
gn(m)=k((n1k)+(n1k1))ykkm=gn1(m)+yj(mj)gn1(j)

Gn(z)=kgn(k)zk/k! ,则 Gn(z)=(yez+1)Gn1(z)
于是多项式快速幂即可。。。。理论上这里是 O(mlogm) 的。。。 常数顶两个log
然而这个题他多项式给的是点值。。。所以要这么做的话还得写个快速插值。。。
这样就成功把所有多项式操作都写进来啦
复杂度就变成了 O(mlog2m) 。。。

要不是我不(lan)会(de)写(xie)快速插值可能就上这玩意了。。。
秉着【出题人一定不会写这么毒瘤的东西】的想法直接用点值来推。。。也能做。。而且复杂度更优秀了。。(当然是在给了点值的情况下。。。)

【正常(?)做法】
考虑 f(x) 的牛顿表示,将系数反演后代入,得

answer=k=0nj=0mi=0j(1)ji(ji)f(i)(kj)(nk)xk(1x)nk=j=0m(i(ji)(1)jif(j))(k=0(nk)(kj)xk(1x)nk)=j=0m(nj)j!([zj]E(z)F(z))(k=0(njkj)xk(1x)nk)=j=0m(nj)j!([zj]E(z)F(z))(k=0nj(njk)xk+j(1x)njk)=j=0m(nj)j!xj[zj]E(z)F(z)

其中 E(z)=k(1)kzk/k!,F(z)=kf(k)/k!
于是只需要算 E(Z) F(Z) 的卷积即可。。。时间复杂度就变成了 O(mlogm) 。。。
不太懂为啥 m 只出到了2e4啊。。。怕不是std真的是上面那个搞笑做法。。。

【主要代码】


int N , len;
arr rev , wn , f , e;

inline void init(int n , int m) {
    for (N = 1 , len = 0; N <= n + m; N <<= 1 , len ++);
    For (i , 0 , N) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (len - 1));
    int g = Pow(G , (mod - 1) / N);
    wn[0] = 1; For (i , 1 , N) wn[i] = mul(wn[i - 1] , g);
}

inline void dft(int *a , int n , int v) {
    For (i , 0 , n) if (i < rev[i]) swap(a[i] , a[rev[i]]);
    for (int s = 2 , i = 1; s <= n; s <<= 1 , i ++) {
        int g = wn[1 << (len - i)];
        for (int k = 0; k < n; k += s) {
            int w = 1;
            For (j , 0 , s / 2) {
                int u = a[k + j] , t = mul(w , a[k + j + s / 2]);
                a[k + j] = add(u , t) , a[k + j + s / 2] = dec(u , t);
                w = mul(w , g);
            }
        }
    }
    if (v == -1) {
        int w = Pow(n , mod - 2);
        For (i , 0 , n) a[i] = mul(a[i] , w);
    }
}

int n , m , x;
arr frac , invF;

void input() {
    n = rd() , m = rd() , x = rd();

    frac[0] = 1;
    rep (i , 1 , m) frac[i] = mul(frac[i - 1] , i);
    invF[m] = Pow(frac[m] , mod - 2);
    per (i , m , 1) invF[i - 1] = mul(invF[i] , i);

    rep (i , 0 , m) f[i] = mul(rd() , invF[i]);
    rep (i , 0 , m) e[i] = (i & 1) ? mod - invF[i] : invF[i];
}

void solve() {
    init(m , m);

    dft(f , N , 1) , dft(e , N , 1);
    For (i , 0 , N) f[i] = mul(f[i] , e[i]);
    reverse(wn + 1 , wn + N);
    dft(f , N , -1);

    int ans = 0;
    int ff = 1 , tt = 1;
    rep (i , 0 , m) {
        int tmp = mul(ff , tt);
        tmp = mul(tmp , f[i]);
        ans = add(ans , tmp);

        ff = mul(ff , n - i);
        tt = mul(tt , x);
    }

    printf("%d\n" , ans);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值