【GDOI2020模拟01.17】小 ω 玩游戏 (容斥+EGF)

小 ω 正在玩一个游戏。
小 ω 有一个 n 行 m 列的网格,初始每个方格中都有数字 0。她需要执行 q 次操作,每次操作可以选择其中一个方格 (x, y),然后先将第 x 行的数全部 +1,接着将第 y 列的数全部 +1。
小 ω 想知道有多少种执行操作的方式能使最后的网格中有不超过 k 个奇数。
两种方式不同当且仅当存在某一步中选择的方格坐标不同。

\(1<=n,m<=2e5,q<=10^{18}\)



考虑行列分开,对行,算出\(f(x)\)表示恰好x行奇数的方案数,对列同理,算出设为g。

有了f和g就可以直接解个不等式然后前缀和统计。

考虑有n行,有p行奇数的方案数,直接列出EGF:

\(f[p]=({e^x-e^{-x}\over 2})^p*({e^x+e^{-x}\over 2})^{n-p}[x^q]*q!*C_n^p\)

暴力展开是\(O(n^3)\)的。

考虑先求出\(({e^x-e^{-x}\over 2})^n\),然后每次除除乘乘就可以做到\(O(n^2)\)的。

然后优化不了了,此时应该考虑容斥:

至少p个奇数行的EGF就很简单了:

\(f2(p)=({e^x-e^{-x}\over 2})^p*e^{x(n-p)}[x^q]*q!*C_n^p\)

\(=\sum_{i=0}^p C_{p}^i*(-1)^{p-i}*e^{xi-x(p-i)}/2^p*e^{x(n-p)}[x^q]*q!*C_n^p\)

\(=\sum_{i=0}^p C_p^i*(-1)^{p-i}*e^{(n-2(p-i))x}[x^q]/*q!/2^p*C_n^p\)

\(=\sum_{i=0}^pC_p^i*(-1)^{p-i}*(n-2(p-i))^q/2^p*C_{n}^p\)

显然可以卷积求。

然后有\(f2[n]=\sum_{i>=n}f[i]*C_{i}^n\)

所以\(f[n]=\sum_{i>=n}f2[i]*C_{i}^n*(-1)^{i-n}\)

再做一个卷积就可以求出f。

#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;
}

const int nm = 1 << 19;

int r[nm]; ll w[nm];
ll a[nm], b[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;
    }
}
void fft(ll *a, ll *b, int n) {
    dft(a, n, 1); dft(b, n, 1);
    ff(i, 0, n) a[i] = a[i] * b[i] % mo;
    dft(a, n, -1);
}

const int N = 2e5 + 5;

int n, m; ll q, k;
ll f[N], g[N], s1[N], s2[N];

ll fac[N], nf[N];

ll s[N];

ll C(int n, int m) {
    return fac[n] * nf[m] % mo * nf[n - m] % mo;
}

void calc(ll *f, 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;

    int tt = 0;
    while((1 << (++ tt)) <= 2 * n);

    memset(a, 0, sizeof a);
    memset(b, 0, sizeof b);
    fo(i, 0, n) a[i] = nf[i], b[i] = (i & 1 ? -1 : 1) * ksm(n - 2 * i, q) * nf[i] % mo;
    fft(a, b, 1 << tt);
    ll ni2 = ksm(2, mo - 2), s = 1;
    fo(i, 0, n) a[i] = a[i] * fac[i] % mo * s % mo * C(n, i) % mo, s = s * ni2 % mo;
    ff(i, n + 1, 1 << tt) a[i] = 0;
    memset(b, 0, sizeof b);
    fo(i, 0, n) a[i] = a[i] * fac[i] % mo, b[n - i] = nf[i] * (i & 1 ? -1 : 1);
    fft(a, b, 1 << tt);
    fo(i, 0, n) f[i] = a[i + n] * nf[i] % mo;
}

void End() {
    s2[0] = g[0]; fo(i, 1, m) s2[i] = (s2[i - 1] + g[i]) % mo;
    ll ans = 0;
    for(ll x = 0; x <= n; x ++) {
        int xs = n - 2 * x;
        if(xs == 0) {
            if(x * m <= k) ans += f[x] * s2[m] % mo;
        } else
        if(xs > 0) {
            ll t = floor((long double) (k - x * m) / xs);
            t = min(t, (ll) m);
            if(t >= 0) ans += f[x] * s2[t] % mo;
        } else {
            ll t = ceil((long double) (k - x * m) / xs);
            if(t <= m) ans += f[x] * (t > 0 ? (s2[m] - s2[t - 1]) : s2[m]) % mo;
        }
    }
    ans = (ans % mo + mo) % mo;
    pp("%lld\n", ans);
}

int main() {
    freopen("play.in", "r", stdin);
    freopen("play.out", "w", stdout);
    build();
    scanf("%d %d %lld %lld", &n, &m, &q, &k);
    calc(f, n); calc(g, m);
    End();

}

原文地址:https://www.cnblogs.com/coldchair/p/12207373.html

时间: 2024-07-30 21:00:40

【GDOI2020模拟01.17】小 ω 玩游戏 (容斥+EGF)的相关文章

6439. 【GDOI2020模拟01.17】小 ω 数排列

题目描述 Description Input Output Sample Input Sample Input1 4 10 3 6 2 9 Sample Input2 8 35 3 7 1 5 10 2 11 6 Sample Output Sample Output1 6 [样例 1 解释] 共有 6 个排列符合条件,它们是 (1, 3, 2, 4),(2, 4, 1, 3),(3, 1, 2, 4),(3, 1, 4, 2),(4, 2, 1, 3),(4, 2, 3, 1). Sample

6441. 【GDOI2020模拟01.17】小 ω 维护序列

Description Input Output 输出到标准输出流中. 若干行,对于每个操作 1 和操作 5,输出一个数表示答案. Sample Input Sample Input1 5 8 1 2 3 2 1 1 1 3 5 1 5 2 2 4 1 2 4 3 3 4 0 5 1 1 2 1 1 5 Sample Input2 10 15 5 4 3 5 4 1 5 4 3 1 2 8 580347 4 6 503576 1 2 5 5 8 11 1 2 6 4 7 565239 3 6 3

【GDOI2020模拟01.16】划愤(nim积+行列式)

https://gmoj.net/senior/#contest/show/2989/1 先考虑n=2时怎么做,打表找规律找了半天找不出来. 赛后才知道这是nim积. 定义\(x?y\)为\(sg(x,y)\). 有一坨性质: \(x,y<2^{2^k},x?y<2^{2^k}\) \(2^{2^k}?2^{2^k}={3 \over 2}2^{2^k}\) 可以把?看做乘法,\(⊕\)(异或)看做加法,所以还有分配律. 求\(x?y(x>y)\),设\(k\)为最大的\(k\)满足\(

6442. 【GDOI2020模拟01.18】钩子

题目描述 Description Input Output Sample Input Sample Input1 3 1000000007 Sample Input2 4 1000000007 Sample Output Sample Output1 0 1 0 500000004 0 500000004 500000004 0 500000004 Sample Output2 0 500000004 500000004 0 333333336 166666668 166666668 33333

6445. 【GDOI2020模拟01.19】String

题目 正解 一听到正解是NTT,我心态崩了. 我特么知道是NTT都不知道该怎么做!哪里像个卷积了? 好吧,是我孤陋寡闻-- 设两个字符串分别为\(A\)和\(B\) 可以考虑试着计算出\(A\)每个子串和\(B\)的相似度(就是位置相同.字母相同的个数),直接统计就完事了. 看到字符集这么小,就可以对于每个字母分开考虑. 假如\(A_i=B_j\),那么以\(A_{i-j+1}\)开头的子串就有\(1\)的贡献. 这样一来,看起来就很像是个卷积了. 搞完之后将贡献加起来,统计即可. 总结 还是没

【GDOI2020模拟01.16】树上的鼠 (博弈+长链剖分优化dp)

https://gmoj.net/senior/#contest/show/2989/2 思考什么时候先手会赢. 一开始双方都不会希望走到直径的端点上,因为那样对方就可以走直径而使自己输掉. 删掉直径的端点,考虑剩下的树的子问题. 如果又走到端点去了,对面就走到另外一个端点,那我就走到下一层的直径端点去了. 所以大家一直都不想走到直径端点. 一直删,如果最后只剩1一个点,说明先手必败,否则先手必胜. 如果是一条链,就是链的两边的长度不等先手就必胜. 如果是一棵树,考虑随便找一条直径,每次删去它的

6444. 【GDOI2020模拟01.18】树高

题目 正解 这题也不是给人写出来的-- 先不要考虑操作二. 有一种比较新奇的思路:将点的颜色挂在边上,然后搞出个边的连通块. 这些连通块的维护是很舒服的,直接上数据结构即可. 考虑边的连通块和点的连通块的关系. 假如有\(x\)和\(y\)和\(z\)三个点相连,\(x\)为\(y\)父亲,\(y\)为\(z\)父亲. \((x,y)\)和\((y,z)\)的颜色相同,意味着\(y\)和\(z\)的颜色相同. 推广一下,我们可以发现,对于一个边连通块而言,除了根节点(需要特判是不是整棵树的根节点

6447. 【GDOI2020模拟01.19】sort

题目 正解 这题一看也是不能写的题目-- 用个平衡树来维护. 平衡树维护的是一个\(Trie\)的序列.每个\(Trie\)表示这段区间中所有数都会排序一遍. 进行各种操作时,首先会将至多两个节点的\(Trie\)分裂.分裂\(Trie\)会新增\(O(\lg n)\)个节点. 然后将整段区间旋到一棵子树内,然后打标记.平衡树和\(Trie\)上都要打标记. 排序是时候将若干个\(Trie\)合并成一个. 由于这些\(Trie\)是带标记的,所以要将标记下传.\(Trie\)树上标记下传时,如果

6438. 【GDOI2020模拟01.16】树上的鼠

题目 由于时间过于久远,而且题面本身也很清晰,所以就懒得另外叙述题目大意了(还有思考历程). 正解 先考虑一条链的情况(长度为奇数,这里的长度是指点的数量): 如果根在中点,先手无论移到哪里,后手都可以移到它的对称点去. 此时先手必败: 如果根不在中点,先手只要一开始移到中点,先手就赢了. 若长度为偶数,就将中间的两个点都看成中点. 先手第一步先移到离根比较远的那个中点上,以后就用一样的策略,每次到达对方的对称点.所以偶数时先手必胜. 然后这就可以推广到一棵树的情况. 可以发现先手必败的情况当且