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]]++;
}

[AGC001E] BBQ Hard题解的更多相关文章

  1. [Agc001E] BBQ Hard

    [Agc001E] BBQ Hard 题目大意 给定\(n\)对正整数\(a_i,b_i\),求\(\sum_{i=1}^{n-1} \sum_{j=i+1}^n \binom{a_i+b_i+a_j ...

  2. AtCoder AGC001E BBQ Hard (DP、组合计数)

    题目链接: https://atcoder.jp/contests/agc001/tasks/agc001_e 题解: 求\(\sum^n_{i=1}\sum^n_{j=i+1} {A_i+A_j+B ...

  3. AGC001E BBQ Hard 组合、递推

    传送门 题意:给出长度为$N$的两个正整数序列$A_i,B_i$,求$\sum\limits_{i=1}^N \sum\limits_{j=i+1}^N C_{A_i+A_j+B_i+B_j}^{A_ ...

  4. [agc001E]BBQ Hard[组合数性质+dp]

    Description 传送门 Solution 题目简化后要求的实际上是$\sum _{i=1}^{n-1}\sum _{j=i+1}^{n}C^{A[i]+A[j]}_{A[i]+A[j]+B[i ...

  5. agc001E - BBQ Hard(dp 组合数)

    题意 题目链接 Sol 非常妙的一道题目. 首先,我们可以把\(C_{a_i + b_i + a_j + b_j}^{a_i + a_j}\)看做从\((-a_i, -b_i)\)走到\((a_j, ...

  6. [AGC001E]BBQ Hard 组合数学

    题目描述 Snuke is having another barbeque party. This time, he will make one serving of Skewer Meal. He ...

  7. AGC001 E - BBQ Hard 组合数学

    题目链接 AGC001 E - BBQ Hard 题解 考虑\(C(n+m,n)\)的组合意义 从\((0,0)\)走到\((n,m)\)的方案数 从\((x,y)\)走到\((x+n,y+m)\)的 ...

  8. AGC01 A - BBQ Easy

    目录 题目链接 题解 代码 题目链接 AGC01 A - BBQ Easy 题解 贪心 排序之后从大到小,没两组取小的那个 代码 #include<cstdio> #include< ...

  9. NOIp2018模拟赛三十八

    爆〇啦~ A题C题不会写,B题头铁写正解: 随手过拍很自信,出分一看挂成零. 若要问我为什么?gtmdsubtask! 神tm就一个subtask要么0分要么100,结果我预处理少了一点当场去世 难受 ...

  10. (浙江金华)Day 1 组合数计数

    目录 Day 1 组合计数 1.组合数 (1).C(n,m) 读作n选m,二项式系数 : (2).n个东西里选m个的方案数 不关心选的顺序: (3).二项式系数--->多项式系数: 2.组合数计 ...

随机推荐

  1. SAP transformation特殊字符

    unicode 0000 在transformation中总被翻译成,这个转义在其他语法中不存在,所以总是报错.

  2. 看看CabloyJS是如何异步加载并执行go wasm模块的

    介绍 CabloyJS提供了一个内置模块a-wasmgo,将go wasm模块的异步加载运行机制进行了封装,使我们可以非常方便的在CabloyJS项目中引入go wasm,从而支持更多的业务场景开发 ...

  3. springboot条件注册Condition注解

    环境识别 import org.springframework.context.annotation.Condition; import org.springframework.context.ann ...

  4. 一文快速回顾 Java 操作数据库的方式-JDBC

    前言 数据库的重要性不言而喻,不管是什么系统,什么应用软件,也不管它们是 Windows 上的应用程序,还是 Web 应用程序,存储(持久化)和查询(检索)数据都是核心的功能. 大家学习数据库时,比如 ...

  5. Android笔记--对话框

    提醒对话框AlertDialog 具体实现: 相关用法: 日期对话框DatePickerDialog DatePicker 具体实现: 使用Dialog选择日期: 时间对话框TimePickerDia ...

  6. 用Java代码验证三门问题

    三门问题(Monty Hall problem)亦称为蒙提霍尔问题,出自美国的电视游戏节目Let's Make a Deal. 问题名字来自该节目的主持人蒙提·霍尔(Monty Hall).参赛者会看 ...

  7. Java面试——Netty

    一.BIO.NIO 和 AIO [1]阻塞 IO(Blocking I/O):同步阻塞I/O模式,当一条线程执行 read() 或者 write() 方法时,这条线程会一直阻塞直到读取一些数据或者写出 ...

  8. 记录hive一次数据倾斜问题的解决以及思考总结

    解决数据倾斜是大数据开发中比较重要的能力,这个现象指的是分布式集群中,由于数据分发的不当,导致某个节点要处理的错误过多,导致整个计算机任务迟迟结束不了,甚至可能节点出现OOM使得任务失败 处理数据倾斜 ...

  9. [数据库]MySQL之备份与恢复【未完待续】

    1 恢复 方式一 source sqlFile.sql 登陆MySQL 创建数据库db (create database db;) 进入/使用 数据库db (use db;) 将要导入的sql文件放到 ...

  10. mysql锁及锁出现总结

    转载请注明出处: 1.按锁粒度分类: 行锁:锁某行数据,锁粒度最小,并发度高:: 行锁是指加锁的时候锁住的是表的某一行或多行记录,多个事务访问同一张表时,只有被锁住的记录不能访问,其他的记录可正常访问 ...