博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
AtCoder Grand Contest 018 E - Sightseeing Plan
阅读量:5312 次
发布时间:2019-06-14

本文共 2361 字,大约阅读时间需要 7 分钟。

Description

给出平面上坐标单调不降的三个矩形 \(A,B,C\) ,你需要在 \(A\) 选择一个起点, \(B\) 选择一个位置休息, \(C\) 选择一个终点,期间你可以向上和向右走

求所有选择的方案和

Solution

写起来有点恶心

先考虑一个简单的问题,求 从 \((0,0)\) 出发,走到矩形 \((0,0),(x,y)\) 内任意一点的方案数
\[\sum_{i=0}^{x}\sum_{j=0}^{y}C_{i+j}^{i}\]
用杨辉三角合并得到:
\[\sum_{i=0}^{x}C_{i+y+1}^{i+1}\]
再用杨辉三角合并成:
\[C_{x+y+2}^{x+1}-1\]

这个合并的过程可以抽象的理解为杨辉三角的合并,也可以分析组合意义:

\(\sum_{i=0}^{n}C_{i+x}^{x}\)相当于枚举了一个总数,在这个总数中取 \(x\)
我们可以转化为 \(C_{n+x+1}^{x+1}\), 相当于多取出了一个球,其中第 \(x+1\) 个球的位置作为这个枚举的总数,也就是上式的 \(i+x\)

然后求从 \((0,0)\) 走到矩形 \((x1,y1),(x2,y2)\) 内的任意一点的方案就可以用二维前缀和求出了

再回到这题:

考虑枚举中转点,我们不如枚举进入矩形 \(B\) 的点和走出的点,那么路上经过的点都可以作为休息点,那么算出每一对进出点的贡献再乘上路径长度就行了
设这两个点分别为 \((x1,y1),(x2,y2)\)
那么分三段算就行了 (F(1)+F(2)+F(3))*(x2-x1+y2-y1+1)
实际上把 (x2+y2+1) 和 (-x1-y1) 的贡献分开算就可以做到 \(O(n)\) 的了,至于 \(F(2)\) 的方案是可以由两条路径拼起来的,不需要多做讨论
硬是不能感性理解的话,给出式子:
枚举两个点,要求: \(\sum\sum (x[j]-x[i]+y[j]-y[i]+1)*C_{x[j]-x[i]+y[j]-y[i]}^{x[j]-x[i]}*S_i*T_j\)
其中 \(S_i\) 表示点 \(i\) 达到第一个矩形内所有点的方案, \(T_i\) 表示 点 \(i\) 到第三个矩形的方案
然后我们发现 \(\sum_{j}C_{x[j]-x[i]+y[j]-y[i]}^{x[j]-x[i]}*T_j=T_i\)
那么原式子就跟 \(j\) 无关了,变为 \(\sum(x[i]+y[i]+1)*S_i*T_i-\sum(-x[j]-y[j])*S_j*T_j\)

#include
using namespace std;const int N=2e6+10,mod=1e9+7;int x[10],y[10],Fac[N],inv[N];inline void priwork(){ Fac[0]=inv[0]=inv[1]=1; for(int i=1;i
=mod)x-=mod;}inline int C(int a,int b){ return 1ll*Fac[a]*inv[b]%mod*inv[a-b]%mod;}inline int G(int x,int y){return C(x+y,x);}inline int F(int x1,int y1,int x2,int y2){ return (1ll*G(x2+1,y2+1)-G(x1,y2+1)-G(x2+1,y1)+G(x1,y1))%mod;}int main(){ freopen("pp.in","r",stdin); freopen("pp.out","w",stdout); priwork(); for(int i=1;i<=6;i++)cin>>x[i]; for(int i=1;i<=6;i++)cin>>y[i]; int ans=0; for(int x1=x[3],y1=y[3];x1<=x[4];x1++) add(ans,1ll*F(x1-x[2],y1-1-y[2],x1-x[1],y1-1-y[1])*F(x[5]-x1,y[5]-y1,x[6]-x1,y[6]-y1)%mod*(mod-x1-y1)%mod); for(int x1=x[3],y1=y[3];y1<=y[4];y1++) add(ans,1ll*F(x1-1-x[2],y1-y[2],x1-1-x[1],y1-y[1])*F(x[5]-x1,y[5]-y1,x[6]-x1,y[6]-y1)%mod*(mod-x1-y1)%mod); for(int x2=x[3],y2=y[4];x2<=x[4];x2++) add(ans,1ll*F(x2-x[2],y2-y[2],x2-x[1],y2-y[1])*F(x[5]-x2,y[5]-y2-1,x[6]-x2,y[6]-y2-1)%mod*(x2+y2+1)%mod); for(int x2=x[4],y2=y[3];y2<=y[4];y2++) add(ans,1ll*F(x2-x[2],y2-y[2],x2-x[1],y2-y[1])*F(x[5]-x2-1,y[5]-y2,x[6]-x2-1,y[6]-y2)%mod*(x2+y2+1)%mod); cout<
<

转载于:https://www.cnblogs.com/Yuzao/p/8717898.html

你可能感兴趣的文章
winXP下安装opensshd服务
查看>>
20130409和陈讨论面试题
查看>>
KO学习重点
查看>>
mysql的隐式转化
查看>>
UIAlertView浅谈
查看>>
将txt文件转换成EXCEL文件的方法
查看>>
图片上传后台实现方法
查看>>
MapXtrem + Asp.net 地图随窗体改变大小
查看>>
AdaBoost算法分析与实现
查看>>
前端知识点总结1
查看>>
在table表格中实现圆角效果
查看>>
文件帮助类(解压,压缩)
查看>>
linux组调度浅析
查看>>
UNIX网络编程——客户/服务器程序设计示范(三)
查看>>
在争取的路上,为艰苦奋斗的适用人群建议
查看>>
opencv2.4.9+vs2010 的配置方法
查看>>
关键字
查看>>
API对接中经常会出现的签名获取,这只是某一种,仅供给有需要的人参考
查看>>
sed简单使用(五)选择性删除
查看>>
1.1 Hello Qt 开始
查看>>