Atcoder 题面传送门 & 洛谷题面传送门

Yet another 思维题……

注意到此题 \(n\) 数据范围很大,但是 \(a_i,b_i\) 数据范围很小,这能给我们什么启发呢?

观察题目所求的组合数的形式,我们可以联想到组合数的组合意义(qwq 似乎 AGC 很喜欢放组合意义的题?涨见识了/cy):\(\dbinom{x+y}{x}\) 为从 \((0,0)\) 出发,只能向上或向右走,到达 \((x,y)\) 的方案数。

于是此题可以转化为,对于 \(\forall i,j\) 求出 \((0,0)\) 出发,到达 \((a_i+a_j,b_i+b_j)\) 的方案数。

但是这样貌似还是不好求,于是考虑再进行一个转化,将坐标轴进行平移,即可转化为 \((-a_i,-b_i)\) 到 \((a_j,b_j)\) 的方案数。

故本题等价于求计算两两点之间的路径条数总和。这个可以用一个简单的 \(dp\) 求出,\(dp_{i,j}\) 表示到达 \((x,y)\) 的路径条数,那么有个显然的转移方程 \(dp_{i,j}=dp_{i-1,j}+dp_{i,j-1}+[is_{i,j}]\),其中 \(is_{i,j}\) 表示 \((i,j)\) 是否为起点。这个 \(dp\) 显然可以在 \(\mathcal O(\max^2\{a_i\})\) 的时间内计算求得。最终答案即为 \(\sum\limits_{i=1}^ndp_{a_i,b_i}\)。

还有个小问题,就是通过以上算法求得的答案为对于任意 \(i,j\),\(\dbinom{a_i+a_j+b_i+b_j}{a_i+a_j}\) 的和,而题目要求 \(i<j\),故需将求得的答案减去 \(i=j\) 部分的答案后再除以 \(2\)。至于怎样求 \(i=j\) 部分的答案……这个就不用说了吧,刚学 OI 的时候就会了(bushi)。

时间复杂度 \(\mathcal O(n+m^2)\),其中 \(m=\max a_i\)。

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned int u32;
typedef unsigned long long u64;
namespace fastio{
#define FILE_SIZE 1<<23
char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
inline void putc(char x){(*p3++=x);}
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc(x%10^48);}
template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);}
void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
}
const int MAXN=2e5;
const int DELTA=2002;
const int MOD=1e9+7;
const int INV2=5e8+4;
int n,a[MAXN+5],b[MAXN+5],dp[DELTA*2+5][DELTA*2+5];
int fac[DELTA*4+5],ifac[DELTA*4+5];
void prework(int k){
fac[0]=ifac[0]=ifac[1]=1;
for(int i=2;i<=k;i++) ifac[i]=1ll*ifac[MOD%i]*(MOD-MOD/i)%MOD;
for(int i=1;i<=k;i++) fac[i]=1ll*fac[i-1]*i%MOD,ifac[i]=1ll*ifac[i]*ifac[i-1]%MOD;
}
int binom(int x,int y){return 1ll*fac[x]*ifac[x-y]%MOD*ifac[y]%MOD;}
int main(){
scanf("%d",&n);prework(DELTA<<2);int ans=0;
for(int i=1;i<=n;i++) scanf("%d%d",&a[i],&b[i]),dp[DELTA-a[i]][DELTA-b[i]]++;
for(int i=1;i<=DELTA*2;i++) for(int j=1;j<=DELTA*2;j++) dp[i][j]=(dp[i][j]+(dp[i-1][j]+dp[i][j-1])%MOD)%MOD;
for(int i=1;i<=n;i++) ans=(ans+dp[DELTA+a[i]][DELTA+b[i]])%MOD;
for(int i=1;i<=n;i++) ans=(ans-binom(a[i]+a[i]+b[i]+b[i],a[i]+a[i])+MOD)%MOD;
ans=1ll*ans*INV2%MOD;printf("%d\n",ans);
return 0;
}

Atcoder Grand Contest 001E - BBQ Hard(组合意义转化,思维题)的更多相关文章

  1. Atcoder Grand Contest 005 E - Sugigma: The Showdown(思维题)

    洛谷题面传送门 & Atcoder 题面传送门 记先手移动棋子的树为红树,后手移动棋子的树为蓝树. 首先考虑一个性质,就是如果与当前红色棋子所在的点相连的边中存在一条边,满足这条边的两个端点在 ...

  2. AtCoder Grand Contest 019 B - Reverse and Compare【思维】

    AtCoder Grand Contest 019 B - Reverse and Compare 题意:给定字符串,可以选定任意i.j且i<=j(当然i==j时没啥卵用),然后翻转i到j的字符 ...

  3. Atcoder Grand Contest 037B(DP,组合数学,思维)

    #include<bits/stdc++.h>using namespace std;const long long mod = 998244353;string s;int a[3000 ...

  4. Atcoder Grand Contest 037C(贪心,优先队列,思维)

    #define HAVE_STRUCT_TIMESPEC//编译器中time.h和phread.h头文件中timespec结构体重名,故加此行#include<bits/stdc++.h> ...

  5. AtCoder Grand Contest 011

    AtCoder Grand Contest 011 upd:这篇咕了好久,前面几题是三周以前写的... AtCoder Grand Contest 011 A - Airport Bus 翻译 有\( ...

  6. AtCoder Grand Contest 031 简要题解

    AtCoder Grand Contest 031 Atcoder A - Colorful Subsequence description 求\(s\)中本质不同子序列的个数模\(10^9+7\). ...

  7. AtCoder Grand Contest 007

    AtCoder Grand Contest 007 A - Shik and Stone 翻译 见洛谷 题解 傻逼玩意 #include<cstdio> int n,m,tot;char ...

  8. AtCoder Grand Contest 006

    AtCoder Grand Contest 006 吐槽 这套题要改个名字,叫神仙结论题大赛 A - Prefix and Suffix 翻译 给定两个串,求满足前缀是\(S\),后缀是\(T\),并 ...

  9. AtCoder Grand Contest 005

    AtCoder Grand Contest 005 A - STring 翻译 给定一个只包含\(ST\)的字符串,如果出现了连续的\(ST\),就把他删去,然后所有位置前移.问最后剩下的串长. 题解 ...

随机推荐

  1. STM32中操作寄存器GPIOB_CRL &= ~( 0x0F<< (4*0))与GPIOB_CRL &=~(0x0F)之间有什么区别吗?

    没有区别,作用相同.只是这样写便于修改和沿用. 对于只用到PB0端口的程序~(0x0f << (4*0)) 和~0x0f没有区别.0x0f <<(4*N) 就是 向左 移动N个 ...

  2. FastAPI 学习之路(三十七)元数据和文档 URL

    你可以在 FastAPI 应用中自定义几个元数据配置. 你可以设定: Title:在 OpenAPI 和自动 API 文档用户界面中作为 API 的标题/名称使用. Description:在 Ope ...

  3. 自定义Push/Pop和Present/Dismiss转场

    项目概述 iOS中最常见的动画无疑是Push和Pop的转场动画了,其次是Present和Dismiss的转场动画. 如果我们想自定义这些转场动画,苹果其实提供了相关的API,在自定义转场之前,我们需要 ...

  4. JavaScript04

    分离绑定事件 使用分离方式绑定元素事件可以使用页面元素与JavaScript代码完全分离,有利于代码分工和维护,是目前开发主流,分为两步: 1.获取需要绑定事件的元素 语法:根据id属性值取元素节点 ...

  5. TCP之拥塞窗口原理

    学过网络相关课程的,都知道TCP中,有两个窗口: 滑动窗口(在我们的上一篇文章中有讲),接收方通过通告发送方自己的可以接受缓冲区大小(这个字段越大说明网络吞吐量越高),从而控制发送方的发送速度. 拥塞 ...

  6. Apache Kafka 学习笔记

    1. 介绍Kafka是由Apache软件基金会开发的一个开源流处理平台,由Scala和Java编写.Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者在网站中的所有动作流数据. 这种动 ...

  7. C++实现红黑树

    红黑树的应用: 利用key_value对,快速查找,O(logn) socket与客户端id之间,形成映射关系(socket, id) 内存分配管理 一整块内存,不断分配小块 每分配一次,就加入到红黑 ...

  8. 恶意代码分析实战四:IDA Pro神器的使用

    目录 恶意代码分析实战四:IDA Pro神器的使用 实验: 题目1:利用IDA Pro分析dll的入口点并显示地址 空格切换文本视图: 带地址显示图形界面 题目2:IDA Pro导入表窗口 题目3:交 ...

  9. 第36篇-return字节码指令

    方法返回的字节码相关指令如下表所示. 0xac ireturn 从当前方法返回int 0xad lreturn 从当前方法返回long 0xae freturn 从当前方法返回float 0xaf d ...

  10. Tenable Nessus 10.0.0 (Unix, Linux) -- #1 漏洞评估解决方案

    请访问原文链接:https://sysin.org/blog/nessus-10/,查看最新版.原创作品,转载请保留出处. 作者:gc(at)sysin.org,主页:www.sysin.org 了解 ...