luoguP4705 玩游戏 分治FFT

1326433-20181227203335995-74973704.png


\[ \begin{aligned} Ans(k) &= \sum \limits_{i = 1}^n \sum \limits_{j = 1}^m \sum \limits_{t = 0}^k \binom{k}{t} a_i^t b_j^{k - t} \\ &= \sum \limits_{t = 0}^k \binom{k}{t} (\sum \limits_{i = 1}^n a_i^t) (\sum \limits_{j = 1}^m b_i^{k - t}) \\ &= k! * \sum \limits_{t = 0}^k (\frac{\sum \limits_{i = 1}^n a_i^t}{t!}) (\frac{\sum \limits_{j = 1}^m b_i^{k - t}}{(k - t)!}) \\ \end{aligned} \]
右边是一个卷积,只需考虑对\(t = 0, 1 ..., n\)求出\(f(t) = \sum \limits_{i = 1}^n a_i^t\)


考虑生成函数\(OGF\)
\[ \begin{aligned} F(x) &= \sum \limits_{i = 0}^{\infty} f(i) * x^i \\ &= \sum \limits_{i = 1}^{\infty} \sum \limits_{j = 1}^{n} a_j^i \\ &= \sum \limits_{i = 1}^n (\sum \limits_{j = 0}^{\infty} (a_ix)^j) \\ &= \sum \limits_{i = 1}^n \frac{1}{1 - a_i x} \end{aligned} \]
那么,现在的问题在于如何求解
\[\sum \limits_{i = 1}^n \frac{1}{1 - a_i x} \]


考虑分治\(FFT\)
一种很好想的思路是先求出\(\sum \limits_{i = 1}^l \frac{1}{1 - a_i x}\)\(\sum \limits_{i = l + 1}^r \frac{1}{1 - a_i x}\)
它们一定是形如\(\frac{A}{B}\)的一个式子,不妨设左边为\(\frac{A}{B}\),右边为\(\frac{C}{D}\)
那么合并之后的形式为\(\frac{AD + BC}{BD}\),然后维护即可

复杂度\(O(n log^2 n)\)


可以发现\[In'(a * b) = (In(a) + In(b))' = In'(a) + In'(b)\]
因此,我们考虑\[In'(\frac{1}{1 - a_i x}) = \frac{-a_i}{1 - a_i x}\]
注意不能在\(In\)中添加常数因子,因此我们只能从这个形式来考虑

\[ \begin{aligned} G(x) &= \sum \limits_{i = 1}^n In'(\frac{1}{1 - a_i x}) \\ &= In ' (\prod \limits_{i = 1}^n \frac{1}{1 - a_i x}) \end{aligned} \]
可以用分治\(FFT\)求出\(G\)
观察数列
\[F(x) = a_i^0 + a_i^1 x^1 + a_i^2 x^2 + a_i^3 x^3 ...\]
\[G(x) = -a_i^1 - a_i^2 x^1 - a_i^3 x^2 + ...\]
因此,\[-xG(x) + n = F(x)\]

然后就可以啦


#include <bits/stdc++.h>
using namespace std;

#define ri register int
#define rep(io, st, ed) for(ri io = st; io <= ed; io ++)
#define drep(io, ed, st) for(ri io = ed; io >= st; io --)

const int sid = 5e5 + 5;
const int mod = 998244353;

#define gc getchar
inline int read() {
    int p = 0, w = 1; char c = gc();
    while(c > '9' || c < '0') { if(c == '-') w = -1; c = gc(); }
    while(c >= '0' && c <= '9') p = p * 10 + c - '0', c = gc();
    return p * w;
}

inline int Inc(int a, int b) { return (a + b >= mod) ? a + b - mod : a + b; }
inline int Dec(int a, int b) { return (a - b < 0) ? a - b + mod : a - b; }
inline int mul(int a, int b) { return 1ll * a * b % mod; }
inline int fp(int a, int k) {
    int ret = 1;
    for( ; k; k >>= 1, a = mul(a, a))
        if(k & 1) ret = mul(ret, a);
    return ret;
}
    
int rev[sid], fac[sid], inv[sid], ivf[sid];
int a[sid], b[sid], ak[sid], bk[sid];
    
inline void init(int Mn, int &n, int &lg) {
    n = 1; lg = 0;
    while(n < Mn) n <<= 1, lg ++;
}
    
inline void NTT(int *a, int n, int opt) {
    for(ri i = 0; i < n; i ++) 
        if(i < rev[i]) swap(a[i], a[rev[i]]);
    for(ri i = 1; i < n; i <<= 1)
    for(ri j = 0, g = fp(3, (mod - 1) / (i << 1)); j < n; j += (i << 1))
    for(ri k = j, G = 1; k < i + j; k ++, G = mul(G, g)) {
        int x = a[k], y = mul(G, a[i + k]);
        a[k] = (x + y >= mod) ? x + y - mod : x + y;
        a[i + k] = (x - y < 0) ? x - y + mod : x - y;
    }
    if(opt == -1) {
        reverse(a + 1, a + n);
        int ivn = fp(n, mod - 2);
        for(ri i = 0; i < n; i ++) a[i] = mul(a[i], ivn);
    }
}
    
int ia[sid], ib[sid];
inline void Inv(int *a, int *b, int n) {
    if(n == 1) { b[0] = fp(a[0], mod - 2); return; }
    Inv(a, b, n >> 1);
    
    int N = 1, lg = 0; init(n + n, N, lg);
    for(ri i = 0; i < N; i ++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (lg - 1));
    for(ri i = 0; i < N; i ++) ia[i] = ib[i] = 0;
    for(ri i = 0; i < n; i ++) ia[i] = a[i], ib[i] = b[i];
    
    NTT(ia, N, 1); NTT(ib, N, 1);
    for(ri i = 0; i < N; i ++) ia[i] = Dec((ib[i] << 1) % mod, mul(ia[i], mul(ib[i], ib[i])));
    NTT(ia, N, -1);
    
    for(ri i = 0; i < n; i ++) b[i] = ia[i];
}
    
inline void Init_Inv(int n) {
    inv[0] = inv[1] = 1;
    for(int i = 2; i <= n; i ++) inv[i] = mul(inv[mod % i], mod - mod / i);
    fac[0] = fac[1] = 1;
    for(int i = 2; i <= n; i ++) fac[i] = mul(fac[i - 1], i);
    ivf[0] = ivf[1] = 1;
    for(int i = 2; i <= n; i ++) ivf[i] = mul(ivf[i - 1], inv[i]);
}
    
inline void wf(int *a, int *b, int n) { for(ri i = 1; i < n; i ++) b[i - 1] = mul(a[i], i); }
inline void jf(int *a, int *b, int n) { for(ri i = 1; i < n; i ++) b[i] = mul(a[i - 1], inv[i]);}
    
int da[sid], iva[sid];
inline void In(int *a, int *b, int n) {
    for(ri i = 0; i < n + n; i ++) da[i] = iva[i] = 0; 
    Inv(a, iva, n); wf(a, da, n);
    
    int N = 1, lg = 0; init(n + n, N, lg);
    for(ri i = 0; i < N; i ++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (lg - 1));
    
    NTT(da, N, 1); NTT(iva, N, 1);
    for(ri i = 0; i < N; i ++) da[i] = mul(da[i], iva[i]);
    NTT(da, N, -1); jf(da, b, n);
}

int hb[sid], inb[sid];
inline void Exp(int *a, int *b, int n) {
    if(n == 1) { b[0] = 1; return; }
    Exp(a, b, n >> 1);
    
    int N = 1, lg = 0; init(n + n, N, lg);
    for(ri i = 0; i < N; i ++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (lg - 1));
    
    for(ri i = 0; i < N; i ++) inb[i] = hb[i] = 0;
    In(b, inb, n);
    for(ri i = 0; i < n; i ++) hb[i] = Dec(a[i], inb[i]); hb[0] ++;
    
    NTT(inb, N, 1); NTT(hb, N, 1);
    for(ri i = 0; i < N; i ++) inb[i] = mul(inb[i], hb[i]);
    NTT(inb, N, -1);
    
    for(ri i = 0; i < n; i ++) b[i] = inb[i];
}

int Ib[sid], F[sid * 2], pa[sid], pb[sid];
inline void calc(int *a, int *b, int n, int t) {
    int N = 1, lg = 0;
    init(max(n, t) + 5, N, lg);
    for(ri i = 0; i < (N << 1); i ++) F[i] = 0;
    for(ri i = 0; i < n; i ++) F[2 * i] = 1, F[2 * i + 1] = mod - a[i + 1];
    for(ri i = n; i < N; i ++) F[2 * i] = 1;
    for(ri i = 1; i < N; i <<= 1) {
        for(ri j = 0; j < N; j += (i << 1)) {
            int M = 1, lg = 0;
            init((i << 2), M, lg);
            for(ri k = 0; k < M; k ++) rev[k] = (rev[k >> 1] >> 1) | ((k & 1) << (lg - 1));
            for(ri k = 0; k < M; k ++) pa[k] = pb[k] = 0;
            for(ri k = 0; k < (i << 1); k ++) 
                pa[k] = F[(j << 1) + k], pb[k] = F[(j << 1) + (i << 1) + k];
            NTT(pa, M, 1); NTT(pb, M, 1);
            for(ri k = 0; k < M; k ++) pa[k] = mul(pa[k], pb[k]);
            NTT(pa, M, -1);
            for(ri k = 0; k < (i << 2); k ++) F[(j << 1) + k] = pa[k];
        }
    }
    for(ri i = 0; i < N; i ++) Ib[i] = 0;
    In(F, Ib, N); wf(Ib, F, N);
    
    b[0] = n;
    for(ri i = 1; i <= t; i ++) b[i] = mul(mod - F[i - 1], ivf[i]);
}
    
inline void solve(int n, int m, int t) {
    int N = 1, lg = 0;
    init(t + t + 5, N, lg);
    for(ri i = 0; i < N; i ++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (lg - 1));
    
    NTT(ak, N, 1); NTT(bk, N, 1);
    for(ri i = 0; i < N; i ++) ak[i] = mul(ak[i], bk[i]);
    NTT(ak, N, -1);
        
    int ivnm = fp(mul(n, m), mod - 2);
    for(ri i = 1; i <= t; i ++) 
        printf("%d\n", mul(mul(ak[i], fac[i]), ivnm));
}
    
int main() {
    int n = read(), m = read();
    rep(i, 1, n) a[i] = read();
    rep(i, 1, m) b[i] = read();
    Init_Inv(500000);
    int t = read(); 
    calc(a, ak, n, t); calc(b, bk, m, t);
    solve(n, m, t);
    return 0;
}

请无视中间的exp

转载于:https://www.cnblogs.com/reverymoon/p/10187388.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
辽B代驾管理系统对代驾订单管理、用户咨询管理、代驾订单评价管理、代驾订单投诉管理、字典管理、论坛管理、公告管理、新闻信息管理、司机管理、用户管理、管理员管理等进行集中化处理。经过前面自己查阅的网络知识,加上自己在学校课堂上学习的知识,决定开发系统选择小程序模式这种高效率的模式完成系统功能开发。这种模式让操作员基于浏览器的方式进行网站访问,采用的主流的Java语言这种面向对象的语言进行辽B代驾管理系统程序的开发,在数据库的选择上面,选择功能强大的Mysql数据库进行数据的存放操作。辽B代驾管理系统的开发让用户查看代驾订单信息变得容易,让管理员高效管理代驾订单信息。 辽B代驾管理系统具有管理员角色,用户角色,这几个操作权限。 辽B代驾管理系统针对管理员设置的功能有:添加并管理各种类型信息,管理用户账户信息,管理代驾订单信息,管理公告信息等内容。 辽B代驾管理系统针对用户设置的功能有:查看并修改个人信息,查看代驾订单信息,查看公告信息等内容。 辽B代驾管理系统针对管理员设置的功能有:添加并管理各种类型信息,管理用户账户信息,管理代驾订单信息,管理公告信息等内容。 辽B代驾管理系统针对用户设置的功能有:查看并修改个人信息,查看代驾订单信息,查看公告信息等内容。 系统登录功能是程序必不可少的功能,在登录页面必填的数据有两项,一项就是账号,另一项数据就是密码,当管理员正确填写并提交这二者数据之后,管理员就可以进入系统后台功能操作区。项目管理页面提供的功能操作有:查看代驾订单,删除代驾订单操作,新增代驾订单操作,修改代驾订单操作。公告信息管理页面提供的功能操作有:新增公告,修改公告,删除公告操作。公告类型管理页面显示所有公告类型,在此页面既可以让管理员添加新的公告信息类型,也能对已有的公告类型信息执行编辑更新,失效的公告类型信息也能让管理员快速删除。新闻管理页面,此页面提供给管理员的功能有:新增新闻,修改新闻,删除新闻。新闻类型管理页面,此页面提供给管理员的功能有:新增新闻类型,修改新闻类型,删除新闻类型。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值