传送门.

题解:

考虑若最后的总伤害数是s,那么就挡板分配一下,方案数是\(C_{s-1}^{n-1}\)。

那么问题在于总伤害数很大,不能一个一个的算。

\(C_{s-1}^{n-1}\)的OGF是\({x^{n-1}\over (1-x)^n}\)

由\(F=FA+R->F={R \over 1-A}\)

得到递推式\(A=1-(1-x)^n\),前面的项可以用组合数算出。

那么每次就是常系数齐次递推,每次搞的时候取模就好了。

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

题解给出了更加巧妙的方法,我们不直接求\(s\)伤害的方案数。

考虑\(f(x)\)表示任意伤害下, 分配给x个人的方案数。

当合并\(f、g\)两堆伤害时时,由于中间可以攃挡板,可以不插,所以就是\(f*g*(1+x)\)。

用NTT卷积,每次算完后只用保留前n项。

直接套快速幂是\(O(log^2)\)的,但是可以用exp优化。

初值利用这个式子就好了\(\sum_{i=y}^xC_{i}^y=C_{x+1}^{y+1}\)。

直到现在我才意识到杨辉三角的一条对角线和一列的求法是一样的,由于翻转一下就好了。

Code:

#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, B = y; i <= B; i ++)
#define ff(i, x, y) for(int i = x, B = y; i < B; i ++)
#define fd(i, x, y) for(int i = x, B = y; i >= B; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std; const int mo = 998244353; ll ksm(ll x, ll y) {
ll s = 1;
for(; y; y /= 2, x = x * x % mo)
if(y & 1) s = s * x % mo;
return s;
} typedef vector<ll> V;
#define pb push_back
#define si size()
#define re resize namespace ntt {
const int nm = 262144;
ll w[nm], a[nm], b[nm]; int r[nm];
void build() {
for(int i = 1; i < nm; i *= 2) {
w[i] = 1;
ll v = ksm(3, (mo - 1) / 2 / i);
ff(j, 1, i) w[i + j] = w[i + j - 1] * v % mo;
}
}
void dft(ll *a, int n, int f) {
ff(i, 0, n) {
r[i] = r[i / 2] / 2 + (i & 1) * (n / 2);
if(i < r[i]) swap(a[i], a[r[i]]);
} ll b;
for(int i = 1; i < n; i *= 2) for(int j = 0; j < n; j += 2 * i) ff(k, 0, i)
b = a[i + j + k] * w[i + k], a[i + j + k] = (a[j + k] - b) % mo, a[j + k] = (a[j + k] + b) % mo;
if(f == -1) {
reverse(a + 1, a + n);
b = ksm(n, mo - 2);
ff(i, 0, n) a[i] = (a[i] + mo) * b % mo;
}
}
V operator * (V p, V q) {
int n0 = p.si + q.si - 1, n = 1;
while(n < n0) n *= 2;
ff(i, 0, n) a[i] = b[i] = 0;
ff(i, 0, p.si) a[i] = p[i];
ff(i, 0, q.si) b[i] = q[i];
dft(a, n, 1); dft(b, n, 1);
ff(i, 0, n) a[i] = a[i] * b[i] % mo;
dft(a, n, -1);
p.re(n0);
ff(i, 0, n0) p[i] = a[i];
return p;
}
void dft(V &p, int f) {
int n = p.si;
ff(i, 0, n) a[i] = p[i];
dft(a, n, f);
ff(i, 0, n) p[i] = a[i];
}
} using ntt :: operator *;
using ntt :: dft; V qni(V a) {
V b; b.re(1); b[0] = ksm(a[0], mo - 2);
for(int n = 2; n < a.si * 2; n *= 2) {
V c = a; c.re(n); c.re(2 * n); dft(c, 1);
b.re(2 * n); dft(b, 1);
ff(i, 0, 2 * n) b[i] = (2 * b[i] - c[i] * b[i] % mo * b[i]) % mo;
dft(b, -1); b.re(n);
}
b.re(a.si); return b;
} V qd(V a) {
fo(i, 0, a.si - 2) a[i] = a[i + 1] * (i + 1) % mo;
a.re(a.si - 1);
return a;
}
V jf(V a) {
a.re(a.si + 1);
fd(i, a.si - 1, 1) a[i] = a[i - 1] * ksm(i, mo - 2) % mo;
a[0] = 0;
return a;
} V ln(V a) {
int n = a.si;
a = jf(qd(a) * qni(a));
a.re(n);
return a;
} V exp(V a) {
V b; b.re(1); b[0] = 1;
for(int n = 1; n < a.si * 2; n *= 2) {
b.re(n);
V c = a; c.re(n);
V d = ln(b);
ff(i, 0, n) d[i] -= c[i];
d = d * b;
ff(i, 0, n) b[i] = (b[i] - d[i] + mo) % mo;
}
b.re(a.si); return b;
} const int N = 1e5 + 5; int n, m, a[N], b[N];
ll fac[N], nf[N]; void build(int n) {
fac[0] = 1;
fo(i, 1, n) fac[i] = fac[i - 1] * i % mo;
nf[n] = ksm(fac[n], mo - 2);
fd(i, n, 1) nf[i - 1] = nf[i] * i % mo;
} V p; V mul(V a, V b) {
a = a * b;
a.re(m);
fd(i, m - 1, 1) a[i] = (a[i] + a[i - 1]) % mo;
return a;
} V c; V ksm(V x, int y) {
if(y == 1) return x;
ll xc = x[0]; ll nc = ksm(xc, mo - 2);
ff(i, 0, m) x[i] = x[i] * nc % mo;
x = ln(x);
ff(i, 0, m) x[i] = x[i] * y % mo;
x = exp(x);
xc = ksm(xc, y);
ff(i, 0, m) x[i] = x[i] * xc % mo;
V d = c;
ff(i, 0, m) d[i] = d[i] * (y - 1) % mo;
d = exp(d);
x = x * d; x.re(m);
return x;
} V operator + (V a, V b) {
if(a.si < b.si) a.re(b.si);
ff(i, 0, b.si) a[i] = (a[i] + b[i]) % mo;
return a;
} V ans; int main() {
ntt :: build();
build(1e5);
scanf("%d %d", &m, &n);
c.re(2); c[0] = 1; c[1] = 1;
c.re(m); c = ln(c);
fo(i, 1, n) scanf("%d %d", &a[i], &b[i]);
fo(i, 1, n) {
p.clear(); p.re(m);
ll f = 1;
fo(j, 1, min(b[i], m)) {
f = f * (b[i] - j + 1) % mo;
p[j - 1] = f * nf[j] % mo;
}
p = ksm(p, a[i]);
if(i == 1) ans = p; else ans = mul(ans, p);
}
ll as = (ans[m - 1] % mo + mo ) % mo;
pp("%lld\n", as);
}

Comet OJ - Contest #11 E ffort(组合计数+多项式快速幂)的更多相关文章

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

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

  2. Comet OJ - Contest #11题解

    传送门 \(A\) 咕咕咕 const int N=1e6+5; char s[N],t[N];int n,res; inline bool cmp(const int &x,const in ...

  3. Comet OJ - Contest #11 B题 usiness

    ###题目链接### 题目大意:一开始手上有 0 个节点,有 n 天抉择,m 种方案,在每天中可以选择任意种方案.任意次地花费 x 个节点(手上的节点数不能为负),使得在 n 天结束后,获得 y 个节 ...

  4. Comet OJ - Contest #11 B 背包dp

    Code: #include <bits/stdc++.h> #define N 1005 #define M 2000 #define setIO(s) freopen(s". ...

  5. Comet OJ - Contest #11 A 水题

    Code: #include <bits/stdc++.h> #define N 3000000 using namespace std; char str[N]; int main() ...

  6. Comet OJ - Contest #11 D isaster 重构树+倍增+dfs序+线段树

    发现对于任意一条边,起决定性作用的是节点编号更大的点. 于是,对于每一条边,按照节点编号较大值作为边权,按照最小生成树的方式插入即可. 最后用线段树维护 dfs 序做一个区间查询即可. Code: # ...

  7. Comet OJ - Contest #2 简要题解

    Comet OJ - Contest #2 简要题解 cometoj A 模拟,复杂度是对数级的. code B 易知\(p\in[l,r]\),且最终的利润关于\(p\)的表达式为\(\frac{( ...

  8. Comet OJ - Contest #2简要题解

    Comet OJ - Contest #2简要题解 前言: 我没有小裙子,我太菜了. A 因自过去而至的残响起舞 https://www.cometoj.com/contest/37/problem/ ...

  9. Comet OJ - Contest #4--前缀和

    原题:Comet OJ - Contest #4-B https://www.cometoj.com/contest/39/problem/B?problem_id=1577传送门 一开始就想着暴力打 ...

随机推荐

  1. [转]C# CancellationTokenSource 终止线程

    我们在多线程中通常使用一个bool IsExit类似的代码来控制是否线程的运行与终止,其实使用CancellationTokenSource来进行控制更为好用,下面我们将介绍CancellationT ...

  2. leetcode-165周赛-1275-找出井字棋的获胜者

    题目描述: 自己的提交: class Solution: def tictactoe(self, moves: List[List[int]]) -> str: p = [[0] * 3 for ...

  3. Halo(二)

    @Conditional 满足条件给容器注册Bean(在配置类 @Configuration 的类和方法上配置) 需要实现Condition接口, 实现matches方法 public class L ...

  4. 初识localstorage用法

    最近在做一个类似填报信息的页面,一共有8页,当点击切换到下一页的时候要求把上一页的数据存到本地,以便下次切换到这个页面的时候自动把值填上去,并且在最后一页提交数据的时候直接用localstorage里 ...

  5. CSS分组和嵌套选择器

    CSS 分组 和 嵌套 选择器 分组选择器 在样式表中有很多具有相同样式的元素.直线模组哪家好 h1 {     color:green; } h2 {     color:green; } p { ...

  6. 一些idea

    二分答案似乎和最小生成树有着不可描述的奇怪关系.(滑稽 联赛级别的在矩形上乱搞的题无非几个思路(按出现概率排序):建图,二维前缀和,dp 涉及到求合法区间数的问题往往要用到桶.等差数列等思想,或者尝试 ...

  7. Nginx网络架构实战学习笔记(四):nginx连接memcached、第三方模块编译及一致性哈希应用

    文章目录 nginx连接memcached 第三方模块编译及一致性哈希应用 总结 nginx连接memcached 首先确保nginx能正常连接php location ~ \.php$ { root ...

  8. Struts1.3——Struts入门

    1.Struts的几个基本概念 1.struts是一个开源框架(frameset) 2.struts是一个Web框架 3.struts是一个基于MVC的Web框架 2.为什么有struts 因为我们对 ...

  9. SQLServer 用法简例

      子曰:“温故而知新,可以为师矣.”孔子说:“温习旧知识从而得知新的理解与体会,凭借这一点就可以成为老师了.“ 尤其是咱们搞程序的人,不管是不是全栈工程师,都是集十八般武艺于一身.不过有时候有些知识 ...

  10. 嵌入式C语言4.4 C语言内存空间的使用-多级指针

    多级指针 int **p; 存访地址的地址空间