首页 > 其他分享 >[AGC001E] BBQ Hard题解

[AGC001E] BBQ Hard题解

时间:2023-05-13 22:35:28浏览次数:64  
标签:int 题解 sum Hard SHIFT MAX binom BBQ MOD

Problem

[AGC001E] BBQ Hard

计算:

\[\sum_{i=1}^{n}\sum_{j=i+1}^n\binom{a_i+b_i+a_j+b_j}{a_i+a_j} \]

其中\(n \leq 2 \times 10^5\),\(a_i,b_i \leq 2000\)

Solution

以\(a_i\)代\(a_i+b_i\)则等价于求

\[\sum_{i=1}^{n}\sum_{j=i+1}^n\binom{a_i+a_j}{b_i+b_j} \]

考虑使得式子变得更加对称,我们可以不限制\(i,j\)的相对大小,之后减去\(i=j\)的情况再除以\(2\)即可。

\[\sum_{i = 1}^{n}\sum_{j = i + 1}^{n}\binom{a_i+a_j}{b_i+b_j}= \dfrac{1}{2}\left( \sum_{i = 1}^{n}\sum_{j = 1}^{n}\binom{a_i+a_j}{b_i+b_j}-\sum_{i = 1}^{n}\binom{2a_i}{2b_i}\right) \]

问题转化为求

\[\sum_{i=1}^{n}\sum_{j=1}^n\binom{a_i+a_j}{b_i+b_j} \]

代数法

推导过程

考虑将\(i,j\)拆开分别计算贡献,可以联想到Vandermonde卷积
于是原式转换为

\[\begin{aligned} \sum_{i=1}^{n}\sum_{j=1}^n\binom{a_i+a_j}{b_i+b_j} &=\sum_{i=1}^{n}\sum_{j=1}^n\sum_k\binom{a_i}{b_i-k}\binom{a_j}{b_j+k} \\ &=\sum_k\sum_{i=1}^{n}\sum_{j=1}^n\binom{a_i}{b_i-k}\binom{a_j}{b_j+k} \\ &=\sum_k\left(\sum_{i=1}^{n}\binom{a_i}{b_i-k}\right)\left(\sum_{j=1}^n\binom{a_j}{b_j+k}\right) \\ &=\sum_{k}F(k)F(-k) \end{aligned} \]

其中\(F(k)=\displaystyle\sum_{i=1}^n\binom{t_i}{a_i+k}\)

然后我们容易想到一个\(O(na)\)的做法,那就是直接计算\(F(k)\),注意由于\(k\)的范围是\([-2000,2000]\),所以我们需要将\(k\)平移至\([0,4000]\),这样就可以用一个数组来存储\(F(k)\)了。

for (int k = mink; k <= maxk; ++k) {
    for (int i = 1; i <= n; ++i) {
        if (k + b[i] >= 0 && k + b[i] <= a[i]) {
            F[k + SHIFT] = (F[k + SHIFT] + C[a[i]][k + b[i]]) % MOD;
        }
    }
}

优化

这个也许卡卡常就能过了,但是我们尝试去追求更好的时间复杂度
事实上,我们利用生成函数的相关知识,有

\[\begin{aligned} F(k)&=\sum_{i=1}^n\binom{t_i}{a_i+k}\\ &= \sum_{i=1}^n(1+x)^{a_i}[x^{b_i+k}]\\ &=[x^k]\sum_{i=1}^n(1+x)^{a_i}x^{-b_i}\\ &=[x^k+SHIFT]\sum_{i=1}^n(1+x)^{a_i}x^{-b_i+SHIFT}\\ &=[x^k+SHIFT]\sum_{A}(1+x)^A\sum_{i,a_i=A}x^{-b_i+SHIFT} \end{aligned} \]

其中\([x^i]\)表示\(x^i\)项的系数。
则我们只需要求出

\[\sum_{A}(1+x)^A\sum_{i,a_i=A}x^{-b_i+SHIFT} \]

这个式子可以用秦九韶算法来求,复杂度降低至\(O(a^2)\)

for (int i = 1; i <= n; ++i) {
    bInA[a[i]].push_back(-b[i] + SHIFT);
}
for (int i = maxa; i >= 0; --i) {
    for (int k = 2* SHIFT; k >= 1; --k) {
        F[k] = (F[k] + F[k - 1]) % MOD;
    }
    for (auto bInAi : bInA[i]) {
        F[bInAi] = (F[bInAi] + 1) % MOD;
    }
}

完整代码

#include<iostream>
#include<vector>
using namespace std;
const int MAX_N = 200005, MOD = 998244353, MAX_A = 4000 + 5, SHIFT = 2000;
int ans, n, a[MAX_N], b[MAX_N], maxa, C[MAX_A][MAX_A], mink, maxk;
int fac[MAX_A * 2], inv[MAX_A * 2], invfac[MAX_A * 2];
int F[MAX_A];//from -2000 to 2000, 加上基数2000
int binom(int n, int k) {
    if (n < k) {
        return 0;
    }
    return 1ll * fac[n] * invfac[k] % MOD * invfac[n - k] % MOD;
}
vector<int> bInA[MAX_A];
signed main() {
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i] >> b[i];
        a[i] += b[i];
        maxa = max(maxa, a[i]);
        mink = min(mink, -b[i]);
        maxk = max(maxk, a[i] - b[i]);
    }
    for (int i = 0; i <= maxa; ++i) {
        C[i][0] = 1;
        for (int j = 1; j <= i; ++j) {
            C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MOD;
        }
    }
    /*for (int k = mink; k <= maxk; ++k) {
        for (int i = 1; i <= n; ++i) {
            if (k + b[i] >= 0 && k + b[i] <= a[i]) {
                F[k + SHIFT] = (F[k + SHIFT] + C[a[i]][k + b[i]]) % MOD;
            }
        }
    }*/
    for (int i = 1; i <= n; ++i) {
        bInA[a[i]].push_back(-b[i] + SHIFT);
    }
    for (int i = maxa; i >= 0; --i) {
        for (int k = 2* SHIFT; k >= 1; --k) {
            F[k] = (F[k] + F[k - 1]) % MOD;
        }
        for (auto bInAi : bInA[i]) {
            F[bInAi] = (F[bInAi] + 1) % MOD;
        }
    }

    for (int k = mink; k <= maxk; ++k) {
        ans = (ans + 1ll * F[k + SHIFT] * F[-k + SHIFT] % MOD) % MOD;
    }
    fac[0] = inv[0] = invfac[0] = 1;
    fac[1] = inv[1] = invfac[1] = 1;
    for (int i = 2; i <= maxa * 2; ++i) {
        fac[i] = 1ll * fac[i - 1] * i % MOD;
        inv[i] = 1ll * (MOD - MOD / i) * inv[MOD % i] % MOD;
        invfac[i] = 1ll * invfac[i - 1] * inv[i] % MOD;
    }
    for (int i = 1; i <= n; ++i) {
        ans = (ans - binom(2 * a[i], 2 * b[i]) + MOD) % MOD;
    }
    ans = 1ll * ans * inv[2] % MOD;
    cout << ans << endl;
    return 0;
}

组合意义法

我们可以把这个值看做在网格图上的一点\((−a[i],−b[i])\)走到\((a[j],b[j])\)的方案数。
而网格图走的方案数可以直接递推得到。
那么我们对于每个点把它的坐标取反到第三象限,然后对于整个坐标系计算走到每一个格子的总方案。

递推式与网格路径完全相同

f[i][j] = (1ll * f[i][j] + f[i - 1][j] + f[i][j - 1]) % MOD;

需要注意的是初始条件

for(int i = 1; i <= n; i++){
    f[SHIFT - a[i]][SHIFT - b[i]]++;
} 

标签:int,题解,sum,Hard,SHIFT,MAX,binom,BBQ,MOD
From: https://www.cnblogs.com/520Enterprise/p/17397724.html

相关文章

  • 【题解】Luogu[P3750] [六省联考 2017] 分手是祝愿
    Link→小清新dp题,纪念自己的700ac(一个点只有两个状态开和不开,且按两下相当于没按,我们可以从大到小有亮的就按一下,如果我们按到了不需要按的键,就需要再按一下使他变回来。设\(f_i\)表示\(i\)个正确选择变为\(i-1\)个的期望操作次数。则有\(\dfrac{i}{n}\)概率按到......
  • 【题解】Luogu[P4900] 食堂
    一到推柿子题。题意即求\(\sum\limits^{n}_{i=1}\sum\limits^{i}_{j=1}\left\{\frac{i}{j}\bmodP\right\}\)对于\(\frac{i}{j}\bmodP\)我们知道即为\(i\)乘上\(j\)的逆元,即为\(i\cdot\mathrm{inv}(j)\)故:\[\begin{aligned}\sum^{n}_{i=1}\sum^{i}_{j=1}\l......
  • 【题解】Luogu[P6003] USACO20JAN Loan Repayment S
    模拟赛第一题(9pts考虑暴力。枚举\(x\),对于每个\(x\),模拟\(k\)天,判断其是否合法,找出最大的\(x\)。时间复杂度:\(O(n^2)\)36pts考虑优化先前暴力算法。我们不难发现当\(x\)合法时,必然有合法\(x_1\),当且仅当\(x_1<x\)。故\(x\)具有单调性,考虑二分答案。对于\(x......
  • 【题解】Luogu[P8818] CSP-S 2022 策略游戏
    一道简单区间rmq分类讨论题,考场上最后5分钟想出来,没写出来,退役了……给定两个序列\(A_{1},\dots,A_{n}\);\(B_1,\dots,B_n\)规定\(C_{i,j}=A_i\timesB_i\)。题目说小L和小Q必定选择最优策略,而小L先选,小Q后选,小L要使得\(C_{i,j}\)尽可能大,小Q要使得\(C_{i,j}\)......
  • 【题解】Luogu[P1879] [USACO06NOV]Corn Fields G
    Link→状压dp典题,看数据范围就能多半猜到是状压。\(M\)行\(N\)列很不舒服,本篇题解规定为\(N\)行\(M\)列。因为说没有哪两块草地相连,我们不妨一行一行考虑,一行中每格只可能是\(0\)或\(1\),所以一行的总不同状态数是\(2^M\)。我们用二进制表示每一行的状态,对于每一行,暴......
  • 【题解】Luogu[P1967] NOIP2013 提高组 货车运输
    Link→很容易想到一个暴力做法,就是跑一遍Floyd,\(F_{i,j}\)表示\(i\)到\(j\)最大载重量,转移\(F_{i,j}=\max\{F_{i,j},\min\{F_{i,k},F_{k,j}\}\}\)。显然时间复杂度\(O(n^3)\)是过不了的。我们发现,因为是求两点路径中使得最小值最大,实际上有一些较小的路径是不会走......
  • CF1698F题解
    考虑一个函数\(f(a)\),它的返回值是一个二维数组\(b\),接受值是一个数组\(a\)。对于所有\(i=1\ton-1\)的\(i\),把\(b_{a_i}{a_{i+1}}++\),然后返回\(b\)。\(f(a)!=f(b)\)且\(a_1=b_1,a_n=b_n\)是无解的充要条件,因为显然对于数组的每次翻转操作它的\(f\)返回值都不会变。\(f(a)!=f(b......
  • CF1777D Score of a Tree 题解
    题目简述给你一个\(n\)个结点根为\(1\)的树。在\(t=0\)时,每个结点都有一个值,为\(0\)或\(1\)。在每一个\(t>0\)时,每个结点的值都会变成其子结点在\(t-1\)时的值的异或和。定义\(S(t)\)为\(t\)时所有结点值的和。定义\(F(A)\)为树在\(0\let\le10^......
  • CF1777C Quiz Master题解
    题目简述给定一个长度为\(n\)的正整数序列\(a\),以及一个正整数\(m\)。在序列\(a\)中选出一个长度为子序列(不是子段)\(b\),\(\foralli\in[1,m],\existsb_j,b_j\)能整除\(i\)。求所有满足条件的序列\(b\)的极差(最大值于最小值的差)的最小值;若无满足条件序列\(b\)......
  • Educational Codeforces Round 148 (Rated for Div. 2) A-D 题解
    比赛地址A.NewPalindrome题意:给一个回文串,判断是否能重新排成另一个回文串Solution存不同对的个数即可voidsolve(){ strings; cin>>s; intn=s.length(); set<char>st; for(inti=0;i<n/2;i++) { st.insert(s[i]); } if(st.size()>1)cout<<"YES\n"; els......