STO ZKY ORZ

Description

给定一张网格图和三个矩形,每次只能向上或向右走。你需要从矩形 \(A\) 中的一个点 \(S\) 出发,到达矩形 \(B\) 中的一个点 \(P\) ,在矩形 \(C\) 中的一个点 \(T\) 结束旅程。只要 \(S,P,T\) 不同或者经过的路径不相同均可看作不同的方案。问总方案数。

Solution

一、点到点

如果我们从 \((0,0)\) 出发要走到 \((x,y)\),那方案数就是 \(C(x+y,x)\)。

二、点到矩形

\(F(x,y)\) 表示从 \((0,0)\) 到 \((x,y)\) 的路径条数。

那么有关系 \(F(x,y)=\sum\limits_{i=0}^y F(x-1,i)\)

这个可以理解为枚举在第 \(x-1\) 行的哪个位置向上走了一步,到达第 \(x\) 行,然后直接向右走到终点。

所以就能得到从 \((0,0)\) 到一个矩形 \((x_1,y_1)-(x_2,y_2)\) 的路径条数就是

\(F(x_2+1,y_2+1)-F(x_2+1,y_1)-F(x_1,y_2+1)+F(x_1,y_1)\)

证明就是用上面的式子,保留 \(F(x_2+1,j)\) 和 \(F(x_1,j)\) 往下消,然后发现最后只有矩形内部统计了一遍。

这里还是自己画图手推比较好。

所以点到矩形的方案被我们转化成了点到四个关键点的方案。

三、矩形到矩形

设 \(G\) 为路径条数

那枚举第一个矩形中的所有点,用上边点到矩形的结论,答案就是

\(\sum\limits_{x_1}\sum\limits_{y_1}\sum\limits_{x}\sum\limits_{y} G((x_1,y_1),(x,y))\)

其中 \((x,y)\) 是第二个矩形的四个关键点。

然后交换求和号可以惊奇的发现,这个式子又变成了关键点到第一个矩形的方案数

所以可以 \(O(16)\) 的枚举两个关键点然后计算即可。注意符号!

四、一个矩形经过一个矩形到另一个矩形

推广上面结论

猜测答案就是第一个矩形的四个关键点,到第三个矩形的四个关键点,要求经过第二个矩形 的方案数。

发现如果要经过第二个矩形,那么要么从 \((x,y_3)\) (下边界)进入,要么从 \((x_3,y)\) (左边界)进入。

所以我们枚举进入点。

进入了这个点就一定进入了这个矩形,它到终点的任意路径就都合法了。

注意枚举进入点,以下边界为例,实际上是枚举 \((x,y_3-1)\) 这个点,然后强制要求在这个点向上走一步进入矩形,这样才可以做到不重不漏。

这题好像快做完了...

五、我也不知道叫啥

发现题目的要求是在第二个矩形中选择一个点,而不是找路径条数。一个经过第二个矩形的长度为 \(len\) 的路径对应着 \(len\) 种 \(P\) 点互不相同的路径。

怎么把这个 \(len\) 算进去呢。

把这个 \(len\) 拆开,假设进入点为 \((x_1,y_1)\),离开点为 \((x_2,y_2)\),那么 \(len=(x_2-x_1+y_2-y_1+1)\)

诶这样可以把 \(len\) 的贡献分开计算

那就在枚举进入点和离开点的时候乘一下就吼了。

Code

#include<bits/stdc++.h>
using std::min;
using std::max;
using std::swap;
using std::vector;
typedef double db;
typedef long long ll;
#define pb(A) push_back(A)
#define pii std::pair<int,int>
#define all(A) A.begin(),A.end()
#define mp(A,B) std::make_pair(A,B)
#define inv(X) ksm(X,zky-2)
const int N=2e6+5;
const int zky=1e9+7; int x[8],y[8];
int fac[N],ifac[N]; struct Node{
int x,y,type;
Node(){}
Node(int a,int b,int c=0){x=a,y=b,type=c;}
}node[10]; int ksm(int x,int y,int ans=1){
while(y){
if(y&1) ans=1ll*ans*x%zky;
x=1ll*x*x%zky;y>>=1;
} return ans;
} int getint(){
int X=0,w=0;char ch=getchar();
while(!isdigit(ch))w|=ch=='-',ch=getchar();
while( isdigit(ch))X=X*10+ch-48,ch=getchar();
if(w) return -X;return X;
} int C(int n,int m){
return 1ll*fac[n]*ifac[m]%zky*ifac[n-m]%zky;
} int G(int x1,int x2,int y1,int y2){
return C(abs(x2-x1)+abs(y2-y1),abs(x2-x1));
} int G(Node a,Node b){
return C(abs(a.x-b.x)+abs(a.y-b.y),abs(a.x-b.x));
} int cal(Node a,Node b){
int ans=0;
for(int i=x[3];i<=x[4];i++){
ans=(1ll*ans-1ll*G(a,Node(i,y[3]-1))*G(Node(i,y[3]),b)%zky*(i+y[3])%zky+zky)%zky;
ans=(1ll*ans+1ll*G(a,Node(i,y[4]))*G(Node(i,y[4]+1),b)%zky*(i+y[4]+1)%zky)%zky;
}
for(int i=y[3];i<=y[4];i++){
ans=(1ll*ans-1ll*G(a,Node(x[3]-1,i))*G(Node(x[3],i),b)%zky*(i+x[3])%zky+zky)%zky;
ans=(1ll*ans+1ll*G(a,Node(x[4],i))*G(Node(x[4]+1,i),b)%zky*(i+x[4]+1)%zky)%zky;
} return (1ll*ans*a.type*b.type+zky)%zky;
} signed main(){
fac[0]=ifac[0]=1;
for(int i=1;i<=N-5;i++) fac[i]=1ll*fac[i-1]*i%zky;
ifac[N-5]=inv(fac[N-5]);
for(int i=N-6;i;i--) ifac[i]=1ll*ifac[i+1]*(i+1)%zky;
for(int i=1;i<=6;i++) x[i]=getint();
for(int i=1;i<=6;i++) y[i]=getint();
node[1]=Node(x[1]-1,y[1]-1,1);node[2]=Node(x[2],y[1]-1,-1);
node[3]=Node(x[1]-1,y[2],-1); node[4]=Node(x[2],y[2],1);
node[5]=Node(x[5],y[5],1); node[6]=Node(x[6]+1,y[5],-1);
node[7]=Node(x[5],y[6]+1,-1); node[8]=Node(x[6]+1,y[6]+1,1);
ll ans=0;
for(int i=1;i<=4;i++)
for(int j=5;j<=8;j++)
ans=((ans+cal(node[i],node[j]))%zky+zky)%zky;
printf("%lld\n",ans);
return 0;
}

[AGC 018 E] Sightseeing plan的更多相关文章

  1. AtCoder Grand Contest 018 E Sightseeing Plan

    题意: 给定三个矩形,选定三个点,答案加上第一个点出发经过第二个点在第三个点结束的方案数,只能往右或往下走. 折腾了我半个多下午的题. 设三个矩形为$A,B,C$一个思路是枚举$B$的那个点$s(x, ...

  2. AGC 018E.Sightseeing Plan——网格路径问题观止

    原题链接 鸣谢:AGC 018E.Sightseeing Plan(组合 DP) 本蒟蒻认为,本题堪称网格路径问题观止. 因为涵盖了不少网格路径问题的处理方法和思路. 一句话题意: 给你三个矩形. 三 ...

  3. BZOJ 3709&&AGC 018 C——多段排序的微扰法

    BZOJ 3709• 有n只怪物,你的初始生命值为z.• 为了打败第i只怪物,你需要消耗cost[i]点生命值,但怪物死后会使你恢复val[i]点生命值.• 任何时候你的生命值都不能小于等于0.• 问 ...

  4. AGC 018E.Sightseeing Plan(组合 DP)

    题目链接 \(Description\) 给定三个不相交的矩形\(A(X1,Y1)-(X2,Y2),B(X3,Y3)-(X4,Y4),C(X5,Y5)-(X6,Y6)\),求 从第一个矩形中某点\(a ...

  5. AGC 018 F - Two Trees

    F - Two Trees 链接 题意: 给定两棵都是N个节点的有根树,节点均从1~N标号.给每个标号定一个权值(类似一号点的权值是x,那么两棵树中1号点的权值都是x),使在两棵树满足以任意节点为根的 ...

  6. AGC 018 A - Getting Difference

    题面在这里! 天呐,我已经做了一天水题了mmp 养生最重要,恩. 首先发现最终序列里的元素肯定是 <= max 的,因为无论何时序列里都不会有负数,所以减的话不会变大(反向大只有>2*ma ...

  7. CodeChef题目选讲

    https://wenku.baidu.com/view/2445a0322f60ddccda38a023.html 关键点:不超过7条 根据咕咕原理,所以答案最少是N/7;(N小于49就暴力) 随机 ...

  8. fzyzojP3782 -组合数问题

    这个ai<=2000有点意思 启发我们用O(W^2)的算法 FFT不存在,对应关系过紧 考虑组合意义转化建模,再进行分离 (除以2不需要逆元不懂为啥,但是算个逆元总不费事) 由于终点可能在起点的 ...

  9. 【AtCoder】AGC018

    A - Getting Difference 我们肯定可以得到这些数的gcd,然后判断每个数减整数倍的gcd能否得到K #include <bits/stdc++.h> #define f ...

随机推荐

  1. java多线程系列6 synchronized 加强版 ReentrantLock

    ReentrantLock类是可重入.互斥.实现了Lock接口的锁,它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力.ReenreantLock类的常用方法有: Re ...

  2. python+selenium—webdriver入门(二)

    本文中主要介绍webdriver常见的对象定位方法: 一.对象定位的目的 二.常见的对象定位方法 一.对象定位的目的: 1.操作对象 2.获得对象的属性,如:对象的class属性.name属性等 3. ...

  3. django的母板系统

    一.母板渲染语法 1.变量 {{ 变量 }} 2.逻辑 {% 逻辑语 %} 二.变量 在母板中有变量时,母板引擎会去反向解析找到这个传来的变量,然后替换掉. .(点),在母板中是深度查询据点符,它的查 ...

  4. AI for VS ,美团创新之处分析

    微软在2017中发布了VS Tools for AI,旨在提升用户对于深度学习的需求体验.AI组件可以让我们迅速构建和训练深度学习的Project,其功能主要有开发,调试和部署深度学习和人工智能的解决 ...

  5. Linux下gcc编译控制动态库导出函数小结

    根据说明文档“How To Write Shared Libraries"介绍, 有四种方法: 1. 在方法声明定义时,加修饰:__attribute__((visibility(" ...

  6. bash编程-正则表达式

    正则表达式与通配符有部分相似之处,但正则表达式更复杂也更强大. 通配符用于(完全)匹配文件名,支持通配符的命令有:ls.find.cp等: 正则表达式用于在文件中(包含)匹配字符串,支持的命令有:gr ...

  7. Maven 项目中的 pom.xml 文件内容说明

    下面是一个比较全面的 POM 文件的结构,当然常用的并不需要这么多配置,视自己的项目需求而定. <project xmlns="http://maven.apache.org/POM/ ...

  8. JavaScript实现单张图片上传功能

    前台jsp代码 <%@ page language="java" pageEncoding="UTF-8" contentType="text/ ...

  9. Liferay7 BPM门户开发之25: Liferay7应用程序配置(APPLICATION CONFIGURATION)

    首先有几个概念需要明确.1.第一个概念是这里的应用程序配置不是写XML之类的配置文件,是类似字典的类型化配置这意味着应用程序配置不只是一个字符串键值对的列表.值还可以有类型,如整数列表,字符串列表,一 ...

  10. JavaScript中的 this全面解析

    上一章我们排除了一些对this的错误认识和知道了this是在调用函数时被绑定的,完全取决于函数的调用位置.先介绍两个概念:调用位置和调用栈. 调用栈:就是为了到达当前执行位置所调用的所有函数. 调用位 ...