Comet OJ - Contest #11 E ffort(组合计数+多项式快速幂)
题解:
考虑若最后的总伤害数是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(组合计数+多项式快速幂)的更多相关文章
- Comet OJ - Contest #11 题解&赛后总结
Solution of Comet OJ - Contest #11 A.eon -Problem designed by Starria- 在模 10 意义下,答案变为最大数的最低位(即原数数位的最 ...
- 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 ...
- Comet OJ - Contest #11 B题 usiness
###题目链接### 题目大意:一开始手上有 0 个节点,有 n 天抉择,m 种方案,在每天中可以选择任意种方案.任意次地花费 x 个节点(手上的节点数不能为负),使得在 n 天结束后,获得 y 个节 ...
- Comet OJ - Contest #11 B 背包dp
Code: #include <bits/stdc++.h> #define N 1005 #define M 2000 #define setIO(s) freopen(s". ...
- Comet OJ - Contest #11 A 水题
Code: #include <bits/stdc++.h> #define N 3000000 using namespace std; char str[N]; int main() ...
- Comet OJ - Contest #11 D isaster 重构树+倍增+dfs序+线段树
发现对于任意一条边,起决定性作用的是节点编号更大的点. 于是,对于每一条边,按照节点编号较大值作为边权,按照最小生成树的方式插入即可. 最后用线段树维护 dfs 序做一个区间查询即可. Code: # ...
- Comet OJ - Contest #2 简要题解
Comet OJ - Contest #2 简要题解 cometoj A 模拟,复杂度是对数级的. code B 易知\(p\in[l,r]\),且最终的利润关于\(p\)的表达式为\(\frac{( ...
- Comet OJ - Contest #2简要题解
Comet OJ - Contest #2简要题解 前言: 我没有小裙子,我太菜了. A 因自过去而至的残响起舞 https://www.cometoj.com/contest/37/problem/ ...
- Comet OJ - Contest #4--前缀和
原题:Comet OJ - Contest #4-B https://www.cometoj.com/contest/39/problem/B?problem_id=1577传送门 一开始就想着暴力打 ...
随机推荐
- ps查看和调整优先级
主题ps查看和调整优先级 一查看优先级 nice值越大优先级越低 [root@centos72 ~]# ps axo pid,cmd,ni | head PID CMD NI 1 /usr/lib/s ...
- Echarts mc地图
Echarts mc地图 echarts官网实例: https://gallery.echartsjs.com/editor.html?c=xSNlA5O-zl 效果: 代码: <html> ...
- implements Serializable有什么作用
转自 http://blog.csdn.net/dinghqalex/article/details/46009911
- nginx添加一个server
nginx添加一个server server { listen 80; server_name dev.pccb.com; index index.html index.htm; # rewrite ...
- 集合类不安全之ArrayList
1. 不安全的ArrayList 大家都知道ArrayList线程不安全,怎么个不安全法呢?上代码: public class ContainerNotSafeDemo { public static ...
- Python模块学习之xlrd 读取Excel时传入formatting_info=True报错:NotImplementedError: formatting_info=True not yet implemented
问题:xlrd读取Excel时传入 formatting_info=True 报错 之前我们使用读取xls文件的时候都是使用的xlrd库,但是这个库只能操作 .xls格式,对于后来的 .xlsx的版本 ...
- Python List列表的操作说明
Python中List的N种操作,其简单程度令人叹为观止... C:\Users\rhys>python Python 2.7.14 (v2.7.14:84471935ed, Sep 16 20 ...
- Redis Sentinel用法
1 Redis Sentinel 1.1 哨兵的作用 1. 监控:监控主从是否正常 2. 通知:出现问题时,可以通知相关人员 3. 故障迁移:自动主从切换 4. 统一的配置管理:连接者询问sentin ...
- winserver 2008 找不到回收站的解决办法
桌面新建文件夹,命名为 “回收站.{645ff040-5081-101b-9f08-00aa002f954e}”,就可以了.
- vue中按需引入mint-UI报Error: .plugins[3][1] must be an object, false, or undefined
{ "presets": ["@babel/preset-env", "@babel/preset-react"], "plugi ...