传送门.

题解:

考虑若最后的总伤害数是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. 密码加密与微服务鉴权JWT

    博客学习目标 1.用户注册时候,对数据库中用户的密码进行加密存储(使用 SpringSecurity). 2.使用 JWT 鉴权认证. 一.BCrypt 密码加密 1.常见的加密方式 任何应用考虑到安 ...

  2. hdu1059&poj1014 Dividing (dp,多重背包的二分优化)

    Problem Description Marsha and Bill own a collection of marbles. They want to split the collection a ...

  3. SCP-bzoj-1069

    项目编号:bzoj-1069 项目等级:Safe 项目描述: 戳这里 特殊收容措施: 求凸包后在凸包上旋转卡壳.然而复杂度要求较低,故可直接枚举四边形的一条对角线,另两个顶点在凸包上随这条对角线的移动 ...

  4. Spring学习笔记第一篇——初识Spring

    1.简单介绍 spring的ioc底层是先配置xml文件,接着创建工厂,利用dom4j解析配置文件,最后通过反射完成.大概步骤差不多这样,这些具体代码spring帮你完成了.现在我们只需要配置xml和 ...

  5. react 中使用 JsBarcode 显示条形码

    import React from 'react';import JsBarcode from 'jsbarcode'; export class RefundSheet extends React. ...

  6. 《一头扎进》系列之Python+Selenium框架实战篇7 - 年底升职加薪,年终奖全靠它!Merry Christmas

    1. 简介 截止到上一篇文章为止,框架基本完全搭建完成.那么今天我们要做什么呢????聪明如你的小伙伴或者是童鞋一定已经猜到了,都测试完了,当然是要生成一份高端大气上档次的测试报告了.没错的,今天宏哥 ...

  7. c++简单String类实现

    #include <iostream> #include <string> using namespace std; class String { public: String ...

  8. Java中深度克隆和浅度克隆

    一:使用目的: 就是为了快速构造一个和已有对象相同的副本.如果需要克隆对象,一般需要先创建一个对象,然后将原对象中的数据导入到新创建的对象中去,而不用根据已有对象进行手动赋值操作. 二:Object中 ...

  9. Forgery CodeForces - 1059B

    一道印章刻印的题目: 具体要求:有一个固定的3*3的印章,给你一个墨迹问能用这个印章印出墨迹吗?(一个像素可以多次被上色) 输入:第一行是墨迹的行列规模,接下来是墨迹 输出:If Andrey can ...

  10. Jenkins 搭建篇

    1.Jenkins 介绍 自动化运维工具:saltstack.jenkins.等.因为他们的目标一样,为了我们的软件.构建.测试.发布更加的敏捷.频繁.可靠 如果运维对git不熟,是无法做自动化部署. ...