【学习笔记】[AGC018E] Sightseeing Plan

首先我们只会计算的情况是,给定起点和终点,计算从起点到终点的路径条数。由于起点和终点都是不确定的,因此显然不能直接计算。

然而这道题的本质还是在考察洞察能力 而我在这方面恰巧是比较差的。算法设计毕竟是先验科学。

我们考虑,从一个点走到一个矩形区域的方案数是多少呢?

F x , y F_{x,y} Fx,y表示从 ( 0 , 0 ) (0,0) (0,0)走到 ( x , y ) (x,y) (x,y)的方案数。那么我们有: F x , y = ∑ i = 0 y F x − 1 , i F_{x,y}=\sum_{i=0}^yF_{x-1,i} Fx,y=i=0yFx1,i

这个式子极具启发意义。它告诉我们,可以用到一个位置的方案数,来表示到一堆位置的方案数。这个思想非常重要。

于是我们得到了从 ( 0 , 0 ) (0,0) (0,0)到左下角为 ( a , b ) (a,b) (a,b),右上角为 ( c , d ) (c,d) (c,d)的矩形区域的方案数: F c + 1 , d + 1 − F a , d + 1 − F c + 1 , b + F a , b F_{c+1,d+1}-F_{a,d+1}-F_{c+1,b}+F_{a,b} Fc+1,d+1Fa,d+1Fc+1,b+Fa,b

那么问题转化为给定起点和终点,经过中间矩形区域其中一个点的方案数。我们枚举进入和出去中间矩阵的位置,那么能被选为中转点的数目就是这两个点的曼哈顿距离,注意到坐标是可以分离的,因此将贡献拆开计算即可。

复杂度 O ( n ) O(n) O(n)

优秀的 OIer \text{OIer} OIer 应该是一位优秀的数学家。

猜想,是一个 OIer \text{OIer} OIer 最有力的武器。

#include<bits/stdc++.h> #define fi first #define se second #define ll long long #define pb push_back #define inf 0x3f3f3f3f #define int ll using namespace std; const int mod=1e9+7; const int N=2e6+5; int X1,X2,X3,X4,X5,X6,Y1,Y2,Y3,Y4,Y5,Y6; int fac[N],inv[N],res; struct node{ int X,Y,Z; }; vector<node>v1,v2; int fpow(int x,int y){ int z(1); for(;y;y>>=1){ if(y&1)z=z*x%mod; x=x*x%mod; }return z; } void init(int n){ fac[0]=1;for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%mod; inv[n]=fpow(fac[n],mod-2);for(int i=n;i>=1;i--)inv[i-1]=inv[i]*i%mod; } int binom(int x,int y){ return fac[x]*inv[y]%mod*inv[x-y]%mod; } int G(int a,int b,int c,int d){ assert(a<=c),assert(b<=d); return binom(c+d-a-b,c-a); } int solve(int A,int B,int C,int D){ ll res=0; res=(res-G(A,B,X3,Y3)*(X3+Y3)%mod*G(X3,Y3,C,D)%mod)%mod; for(int i=X3+1;i<=X4;i++){ res=(res-G(A,B,i,Y3-1)*(i+Y3)%mod*G(i,Y3,C,D)%mod)%mod; } for(int i=Y3+1;i<=Y4;i++){ res=(res-G(A,B,X3-1,i)*(X3+i)%mod*G(X3,i,C,D)%mod)%mod; }res=(res+(X4+Y4+1)*G(X4,Y4,C,D)%mod*G(A,B,X4,Y4)%mod)%mod; for(int i=X4-1;i>=X3;i--){ res=(res+G(i,Y4+1,C,D)*(i+Y4+1)%mod*G(A,B,i,Y4)%mod)%mod; } for(int i=Y4-1;i>=Y3;i--){ res=(res+G(X4+1,i,C,D)*(X4+i+1)%mod*G(A,B,X4,i)%mod)%mod; }return res; } signed main(){ ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>X1>>X2>>X3>>X4>>X5>>X6>>Y1>>Y2>>Y3>>Y4>>Y5>>Y6,init(2000000); v1.pb({X1-1,Y1-1,1}),v1.pb({X1-1,Y2,-1}),v1.pb({X2,Y1-1,-1}),v1.pb({X2,Y2,1}); v2.pb({X6+1,Y6+1,1}),v2.pb({X5,Y6+1,-1}),v2.pb({X6+1,Y5,-1}),v2.pb({X5,Y5,1}); int res(0); for(int i=0;i<4;i++)for(int j=0;j<4;j++)res=(res+solve(v1[i].X,v1[i].Y,v2[j].X,v2[j].Y)*v1[i].Z*v2[j].Z)%mod; cout<<(res+mod)%mod; }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530072.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(10)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示