题目传送门:Comet 67E

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

题意简述:

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

题解:

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

\[\begin{aligned}\mathbf{Ans}&=\sum_{a=1}^{\infty}([x^a]G)\cdot\binom{a-1}{m-1}\\&=\sum_{a=0}^{\infty}\!\left([x^{a}]\dfrac{G}{x}\right)\!\cdot\binom{a}{\hat m}\\&=\frac{1}{\hat m!}\sum_{i=0}^{\infty}([x^i]F)i^{\underline{\hat m}}\\\end{aligned}
\]

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

其中 \(G\) 为给己方士兵分配伤害的方案数的 \(\mathbf{OGF}\),即 \(\displaystyle G=\prod_{i=1}^{n}\left[\mathbf{OGF}\left\{0,\underset{b_i}{\underbrace{1,\ldots,1}}\right\}\right]^{a_i}\)。

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

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


下降幂经常出现在多次求导后的多项式中,即 \(\displaystyle f^{(k)}(x)=\sum_{i=k}^{\infty}f_ii^{\underline{k}}\cdot x^{i-k}\)。

那么 \(\displaystyle\sum_{i=0}^{\infty}f_ii^{\underline{\hat m}}=f^{(\hat m)}(1)\)。

据此,则有:

\[\mathbf{Ans}=\frac{1}{\hat m!}F^{(m)}(1)
\]

考虑 \(\displaystyle F=\frac{1}{x}\prod_{i=1}^{n}\left[\mathbf{OGF}\left\{0,\underset{b_i}{\underbrace{1,\ldots,1}}\right\}\right]^{a_i}\) 的 \(\hat m\) 阶导:

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

令 \(f_i=\mathbf{OGF}\left\{0,\underset{b_i}{\underbrace{1,\ldots,1}}\right\}\) ,特别地 \(f_0=\dfrac{1}{x}\),\(a_0=1\),那么有 \(\displaystyle F=\prod_{i=0}^{n}f_i^{a_i}\)。

于是:

\[\begin{aligned}\mathbf{Ans}&=\frac{1}{\hat m}F^{(m)}(1)\\&=\frac{1}{\hat m}\left(\hat m!\left[z^{\hat m}\right]\prod_{i=0}^{n}\left(\sum_{j=0}^{\infty}\frac{f_i^{(j)}}{j!}z^{j}\right)^{a_i}\right)(1)\\&=[z^m]\prod_{i=0}^{n}\left(\sum_{j=0}^{\infty}\frac{f_i^{(j)}(1)}{j!}z^j\right)^{a_i}\end{aligned}
\]

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


接下来考虑如何计算 \(\dfrac{f_i^{(j)}(1)}{j!}\):

对于 \(f_0=\dfrac{1}{x}\),有 \(\left(\dfrac{1}{x}\right)^{(k)}(1)=(-1)^kk!\),所以 \(\dfrac{f_0^{(j)}(1)}{j!}=(-1)^j\)。

对于 \(f_i=\mathbf{OGF}\left\{0,\underset{b_i}{\underbrace{1,\ldots,1}}\right\}\),稍加推导可以得到:

  • \(f_i^{(0)}(1)\),即 \(f_i(1)\),等于 \(b_i\)(显然)。
  • 对于 \(j\ge1\),有 \(f_i^{(j)}(1)=\dfrac{(b_i+1)^{\underline{j+1}}}{j+1}\)(证明略),于是 \(\dfrac{f_i^{(j)}(1)}{j!}=\dfrac{(b_i+1)^{\underline{j+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的更多相关文章

  1. Comet OJ - Contest #11 E ffort(组合计数+多项式快速幂)

    传送门. 题解: 考虑若最后的总伤害数是s,那么就挡板分配一下,方案数是\(C_{s-1}^{n-1}\). 那么问题在于总伤害数很大,不能一个一个的算. \(C_{s-1}^{n-1}\)的OGF是 ...

  2. Comet OJ - Contest #11 题解&赛后总结

    Solution of Comet OJ - Contest #11 A.eon -Problem designed by Starria- 在模 10 意义下,答案变为最大数的最低位(即原数数位的最 ...

  3. Comet技术

    1.Comet是什么? 维基百科: Comet是一种用于web的推送技术,能使服务器实时地将更新的信息传送到客户端,而无须客户端发出请求,目前有两种实现方式,长轮询和iframe流. 说白了就是web ...

  4. 基于 Asp.Net的 Comet 技术解析

    Comet技术原理 来自维基百科:Comet是一种用于web的技术,能使服务器能实时地将更新的信息传送到客户端,而无须客户端发出请求,目前有两种实现方式,长轮询和iframe流. 简单的说是一种基于现 ...

  5. Comet ASP.NET AJAX 示例

    最近公司有个项目,里面要求要用到Comet技术,所以就到网上找了一下相关的资料和文章,发现有些人说用Ajax的长轮询比较好,后来就百度了一下,发现comet貌似就是通过ajax演变而来的,也就是com ...

  6. Asp.net MVC Comet推送

    一.简介 在Asp.net MVC实现的Comet推送的原理很简单. 服务器端:接收到服务器发送的AJAX请求,服务器端并不返回,而是将其Hold住,待到有东西要通知客户端时,才将这个请求返回. 客户 ...

  7. 浅入浅出“服务器推送”之一:Comet简介

    最近有个项目,其中有项需求要从服务器端主动向客户端推送数据,本以为很简单,但在实际做的过程中发现很棘手,并没有想象中的简单.从网上搜索学习,发现主流讲的还是Ajax的长轮询技术或者流技术,websoc ...

  8. comet在asp.net中的实现

    网上有关“服务器推送”的介绍非常多,其中一种实现方式就是采用comet技术,在浏览器与服务端之间建立一个http协议的“长连接”,所谓“长连接”,就是指浏览器到服务端的http请求不会马上得到服务端的 ...

  9. 探求网页同步提交、ajax和comet不为人知的秘密(上篇)

    标题里的技术都是web开发里最常见的技术,但是我想这些常用的技术有很多细节是很多朋友不太清楚的,理解这些细节是我们深入掌握这些技术的一把钥匙,今天我就讲讲我使用这些技术时体会到的这些细节. 同步提交是 ...

随机推荐

  1. [C3] 正则化(Regularization)

    正则化(Regularization - Solving the Problem of Overfitting) 欠拟合(高偏差) VS 过度拟合(高方差) Underfitting, or high ...

  2. vim考场配置

    syntax on set number set mouse=a set autoread set showmatch set autoindent set smartindent set tabst ...

  3. 数据库连接池 DBUtils:

    import pymysqlfrom DBUtils.PooledDB import PooledDB, SharedDBConnectionPOOL = PooledDB ( creator=pym ...

  4. angular6.x 引入echarts

    因为angular2+ 使用 ==typescript==开发,所以想要使用echarts,必须安装echarts针对angular的插件ngx-echarts.本文案列实际效果如上图. 安装ngx- ...

  5. iOS:获取一周7天的日期(年-月-日-星期)

    一.介绍 在开发中,日期的使用绝对是离不了的,跟业务的关联性太强了,例如课程表.有的时候我们不需要课程表,但是需要获取一周7天的日期,这一周内的日期,我觉得有两种理解: 1.获取当天开始的一周日期,当 ...

  6. pip 设置阿里云源

    在~/.pip/pip.conf文件中添加或修改 mkdir ~/.pip [global] index-url = http://mirrors.aliyun.com/pypi/simple/ [i ...

  7. jpa复杂查询groupby失败的原因以及替代方法-20190824

    问题 1  jpa specification 复杂查询,拼接group by 时,分页会触发select  count (*),导致指定select * from table group by 字段 ...

  8. vuex 源码分析(一) 使用方法和代码结构

    Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式,它采用集中式存储管理应用的所有组件的状态,注意:使用前需要先加载vue文件才可以使用(在node.js下需要使用Vue.use(Vuex ...

  9. CodeForce 577B Modulo Sum

    You are given a sequence of numbers a1, a2, ..., an, and a number m. Check if it is possible to choo ...

  10. .NET Core 学习笔记之 WebSocketsSample

    1. 服务端 代码如下: Program: using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; namespace WebS ...