Comet 67E: ffort

Posted pinkrabbit

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Comet 67E: ffort相关的知识,希望对你有一定的参考价值。

题目传送门:Comet 67E

用了个傻逼做法 A 了这题,欢迎观赏睿智做法!

题意简述:

题目说得很清楚了(这次是我不想写了)。

题解:

为了方便,令 \(m\) 为敌人数,\(n\) 为己方士兵种数。设 \(\mathbfAns\) 为答案,则有:

\[\beginaligned\mathbfAns&=\sum_a=1^\infty([x^a]G)\cdot\binoma-1m-1\\&=\sum_a=0^\infty\!\left([x^a]\dfracGx\right)\!\cdot\binoma\hat m\\&=\frac1\hat m!\sum_i=0^\infty([x^i]F)i^\underline\hat m\\\endaligned\]

意即枚举 \(a\) 为打出的伤害数,则将这些伤害分配给敌人的方法数为 \(\dbinoma-1m-1\)

其中 \(G\) 为给己方士兵分配伤害的方案数的 \(\mathbfOGF\),即 \(\displaystyle G=\prod_i=1^n\left[\mathbfOGF\left\0,\undersetb_i\underbrace1,\ldots,1\right\\right]^a_i\)

\([x^a]G\) 就为将伤害分配给己方士兵的方案数。

接下来令 \(\hat m=m-1\)\(F=\dfracGx\),变换求和指标并提出 \(\dfrac1\hat m!\),留下下降幂形式。


下降幂经常出现在多次求导后的多项式中,即 \(\displaystyle f^(k)(x)=\sum_i=k^\inftyf_ii^\underlinek\cdot x^i-k\)

那么 \(\displaystyle\sum_i=0^\inftyf_ii^\underline\hat m=f^(\hat m)(1)\)

据此,则有:

\[\mathbfAns=\frac1\hat m!F^(m)(1)\]

考虑 \(\displaystyle F=\frac1x\prod_i=1^n\left[\mathbfOGF\left\0,\undersetb_i\underbrace1,\ldots,1\right\\right]^a_i\)\(\hat m\) 阶导:

  • 对于 \(\displaystyle t=\prod_i=1^nt_i\)\(k\) 阶导,重复使用乘法法则 \((fg)'=f'g+fg'\) 即可得出:
  • \(\displaystyle t^(k)=\sum_a_1+a_2+\cdots+a_n=k\binomka_1\ldots n\prod_i=1^nt_i^(a_i)\),其中 \(\dbinomka_1\ldots n\) 即为多重组合数。
  • 从生成函数的角度看来,即 \(\displaystyle t^(k)=k![z^k]\prod_i=1^n\sum_j=0^\infty\fract_i^(j)j!z^j\),即每个 \(\t_i^(0),t_i^(1),\ldots\\) 的二项卷积。

\(f_i=\mathbfOGF\left\0,\undersetb_i\underbrace1,\ldots,1\right\\) ,特别地 \(f_0=\dfrac1x\)\(a_0=1\),那么有 \(\displaystyle F=\prod_i=0^nf_i^a_i\)

于是:

\[\beginaligned\mathbfAns&=\frac1\hat mF^(m)(1)\\&=\frac1\hat m\left(\hat m!\left[z^\hat m\right]\prod_i=0^n\left(\sum_j=0^\infty\fracf_i^(j)j!z^j\right)^a_i\right)(1)\\&=[z^m]\prod_i=0^n\left(\sum_j=0^\infty\fracf_i^(j)(1)j!z^j\right)^a_i\endaligned\]

因为 \(n\times m\le 10^5\),所以后面只要算出 \(\dfracf_i^(j)(1)j!\)\(0\le i\le n\)\(0\le j\le m\)),然后多项式快速幂暴力乘即可。


接下来考虑如何计算 \(\dfracf_i^(j)(1)j!\)

对于 \(f_0=\dfrac1x\),有 \(\left(\dfrac1x\right)^(k)(1)=(-1)^kk!\),所以 \(\dfracf_0^(j)(1)j!=(-1)^j\)

对于 \(f_i=\mathbfOGF\left\0,\undersetb_i\underbrace1,\ldots,1\right\\),稍加推导可以得到:

  • \(f_i^(0)(1)\),即 \(f_i(1)\),等于 \(b_i\)(显然)。
  • 对于 \(j\ge1\),有 \(f_i^(j)(1)=\dfrac(b_i+1)^\underlinej+1j+1\)(证明略),于是 \(\dfracf_i^(j)(1)j!=\dfrac(b_i+1)^\underlinej+1(j+1)!\) 可以递推求出。

那么这题就做完了,代码如下,复杂度 \(\mathcal O(nm\log m)\)

#include <cstdio>
#include <algorithm>

typedef long long LL;
const int Mod = 998244353;
const int G = 3, iG = 332748118;
const int MS = 1 << 19;

inline int qPow(int b, int e) 
    int a = 1;
    for (; e; e >>= 1, b = (LL)b * b % Mod)
        if (e & 1) a = (LL)a * b % Mod;
    return a;


inline int gInv(int b)  return qPow(b, Mod - 2); 

int Inv[MS], Fac[MS], iFac[MS];

inline void Init(int N) 
    Fac[0] = 1;
    for (int i = 1; i < N; ++i) Fac[i] = (LL)Fac[i - 1] * i % Mod;
    iFac[N - 1] = gInv(Fac[N - 1]);
    for (int i = N - 1; i >= 1; --i) iFac[i - 1] = (LL)iFac[i] * i % Mod;
    for (int i = 1; i < N; ++i) Inv[i] = (LL)Fac[i - 1] * iFac[i] % Mod;


inline int Binom(int N, int M) 
    if (M < 0 || M > N) return 0;
    return (LL)Fac[N] * iFac[M] % Mod * iFac[N - M] % Mod;


int Sz, InvSz, R[MS];

inline int getB(int N)  int Bt = 0; while (1 << Bt < N) ++Bt; return Bt; 

inline void InitFNTT(int N) 
    int Bt = getB(N);
    if (Sz == (1 << Bt)) return ;
    Sz = 1 << Bt, InvSz = Mod - (Mod - 1) / Sz;
    for (int i = 1; i < Sz; ++i) R[i] = R[i >> 1] >> 1 | (i & 1) << (Bt - 1);


inline void FNTT(int *A, int Ty) 
    for (int i = 0; i < Sz; ++i) if (R[i] < i) std::swap(A[R[i]], A[i]);
    for (int j = 1, j2 = 2; j < Sz; j <<= 1, j2 <<= 1) 
        int wn = qPow(~Ty ? G : iG, (Mod - 1) / j2), w, X, Y;
        for (int i = 0, k; i < Sz; i += j2) 
            for (k = 0, w = 1; k < j; ++k, w = (LL)w * wn % Mod) 
                X = A[i + k], Y = (LL)w * A[i + j + k] % Mod;
                A[i + k] -= (A[i + k] = X + Y) >= Mod ? Mod : 0;
                A[i + j + k] += (A[i + j + k] = X - Y) < 0 ? Mod : 0;
            
        
    
    if (!~Ty) for (int i = 0; i < Sz; ++i) A[i] = (LL)A[i] * InvSz % Mod;


inline void PolyConv(int *_A, int N, int *_B, int M, int *_C) 
    static int A[MS], B[MS];
    InitFNTT(N + M - 1);
    for (int i = 0; i < N; ++i) A[i] = _A[i];
    for (int i = N; i < Sz; ++i) A[i] = 0;
    for (int i = 0; i < M; ++i) B[i] = _B[i];
    for (int i = M; i < Sz; ++i) B[i] = 0;
    FNTT(A, 1), FNTT(B, 1);
    for (int i = 0; i < Sz; ++i) A[i] = (LL)A[i] * B[i] % Mod;
    FNTT(A, -1);
    for (int i = 0; i < N + M - 1; ++i) _C[i] = A[i];


inline void PolyInv(int *_A, int N, int *_B) 
    static int A[MS], B[MS], tA[MS], tB[MS];
    for (int i = 0; i < N; ++i) A[i] = _A[i];
    for (int i = N, B = getB(N); i < 1 << B; ++i) A[i] = 0;
    B[0] = gInv(A[0]);
    for (int L = 1; L < N; L <<= 1) 
        int L2 = L << 1, L4 = L << 2;
        InitFNTT(L4);
        for (int i = 0; i < L2; ++i) tA[i] = A[i];
        for (int i = L2; i < Sz; ++i) tA[i] = 0;
        for (int i = 0; i < L; ++i) tB[i] = B[i];
        for (int i = L; i < Sz; ++i) tB[i] = 0;
        FNTT(tA, 1), FNTT(tB, 1);
        for (int i = 0; i < Sz; ++i) tB[i] = tB[i] * (2 - (LL)tA[i] * tB[i] % Mod + Mod) % Mod;
        FNTT(tB, -1);
        for (int i = 0; i < L2; ++i) B[i] = tB[i];
    
    for (int i = 0; i < N; ++i) _B[i] = B[i];


inline void PolyLn(int *_A, int N, int *_B) 
    static int tA[MS], tB[MS];
    for (int i = 1; i < N; ++i) tA[i - 1] = (LL)_A[i] * i % Mod;
    PolyInv(_A, N - 1, tB);
    InitFNTT(N + N - 3);
    for (int i = N - 1; i < Sz; ++i) tA[i] = 0;
    for (int i = N - 1; i < Sz; ++i) tB[i] = 0;
    FNTT(tA, 1), FNTT(tB, 1);
    for (int i = 0; i < Sz; ++i) tA[i] = (LL)tA[i] * tB[i] % Mod;
    FNTT(tA, -1);
    _B[0] = 0;
    for (int i = 1; i < N; ++i) _B[i] = (LL)tA[i - 1] * Inv[i] % Mod;


inline void PolyExp(int *_A, int N, int *_B) 
    static int A[MS], B[MS], tA[MS], tB[MS];
    for (int i = 0; i < N; ++i) A[i] = _A[i];
    for (int i = N, B = getB(N); i < 1 << B; ++i) A[i] = 0;
    B[0] = 1;
    for (int L = 1; L < N; L <<= 1) 
        int L2 = L << 1, L4 = L << 2;
        for (int i = L; i < L2; ++i) B[i] = 0;
        PolyLn(B, L2, tA);
        InitFNTT(L4);
        for (int i = 0; i < L2; ++i) tA[i] = (!i + A[i] - tA[i] + Mod) % Mod;
        for (int i = L2; i < Sz; ++i) tA[i] = 0;
        for (int i = 0; i < L; ++i) tB[i] = B[i];
        for (int i = L; i < Sz; ++i) tB[i] = 0;
        FNTT(tA, 1), FNTT(tB, 1);
        for (int i = 0; i < Sz; ++i) tA[i] = (LL)tA[i] * tB[i] % Mod;
        FNTT(tA, -1);
        for (int i = 0; i < L2; ++i) B[i] = tA[i];
    
    for (int i = 0; i < N; ++i) _B[i] = B[i];


int M, N;
int Ans[MS], Tmp[MS];

int main() 
    scanf("%d%d", &M, &N), --M;
    Init(M + 2);
    for (int i = 0; i <= M; ++i) Ans[i] = i & 1 ? Mod - 1 : 1;
    while (N--) 
        int a, b;
        scanf("%d%d", &a, &b);
        Tmp[0] = 1;
        int coef = (LL)(b + 1) * gInv(b) % Mod;
        for (int i = 1; i <= M; ++i) 
            coef = (LL)coef * (b - i + 1) % Mod * Inv[i + 1] % Mod;
            Tmp[i] = coef;
        
        PolyLn(Tmp, M + 1, Tmp);
        for (int i = 0; i <= M; ++i) Tmp[i] = (LL)Tmp[i] * a % Mod;
        PolyExp(Tmp, M + 1, Tmp);
        int qwq = qPow(b, a);
        for (int i = 0; i <= M; ++i) Tmp[i] = (LL)Tmp[i] * qwq % Mod;
        PolyConv(Ans, M + 1, Tmp, M + 1, Ans);
    
    int tAns = Ans[M];
    printf("%d\n", tAns);
    return 0;

以上是关于Comet 67E: ffort的主要内容,如果未能解决你的问题,请参考以下文章

Tomcat如何实现Comet

js-Ajax与Comet

GWT 的 Comet 实现

Comet 的客户端技术

如何使用 Flash 实现 Comet

WEB消息推送-comet4j