细节炸的好惨…
根据只能向上或者向右走的性质,我们考虑一种朴素的做法
令f[i][j]表示走到第i列,第j行的路径数
这样做时间复杂度是
O(nm)
的,而且会算重复一些路径,因为对于每个障碍的位置关系都相同的路径是视为同一路径的
先考虑怎么去重
每条路径,除非需要绕过障碍,否则我们都让他保持最低的高度,即贴着底线走,由于其只能向上或右走的性质,别的走法能走到的地方这样走也都能走到,且在这种约束下, 对每个障碍的位置关系相同的路径会收束到一条,就可以做到去重
然后考虑优化复杂度
我们用扫描线从左到右扫过去
如果没有遇到障碍,每条路径都沿着原来的高度走,f[i+1][j]=f[i][j],我们不需要做任何操作
如果遇到了一个障碍,它对在他上方的路径不会有影响,在他下方的路径此时可以选择是否走这个障碍的左边,假设他的高度在l~r,如果r+1此时没有被其他障碍覆盖,记l下面的最高的障碍高度为k,那么高度在k+1~l-1的这些路径可以选择走这个障碍的左边,线段树兹瓷区间求和给r+1加上去,然后把l~r这段高度的路径数量清空
复杂度就变成了 O(n+klogm) ,可以通过此题
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 1100000;
const int maxk = 110000;
const ll Mod = 1e9+7;
int n,m,k;
struct segment
{
ll c,flag;
}seg[maxn<<2];
void pushdown(const int x,const int l,const int r)
{
if(seg[x].flag!=-1)
{
int mid=l+r>>1,lc=x<<1,rc=lc|1;
ll fl=seg[x].flag%Mod; seg[x].flag=-1;
seg[lc].c=(ll)(mid-l+1)*fl%Mod;
seg[lc].flag=fl;
seg[rc].c=(ll)(r-mid)*fl%Mod;
seg[rc].flag=fl;
}
}
void pushup(const int x)
{
int lc=x<<1,rc=lc|1;
seg[x].c=(seg[lc].c+seg[rc].c)%Mod;
}
int lx,rx;
ll v;
void upd(const int x,const int l,const int r)
{
if(rx<l||r<lx) return;
if(lx<=l&&r<=rx)
{
seg[x].c=(ll)(r-l+1)*v%Mod;
seg[x].flag=v;
return;
}
pushdown(x,l,r);
int mid=l+r>>1,lc=x<<1,rc=lc|1;
upd(lc,l,mid); upd(rc,mid+1,r);
pushup(x);
}
void add(const int x,const int l,const int r)
{
if(l==r) { seg[x].c+=v; return; }
int mid=l+r>>1,lc=x<<1,rc=lc|1;
pushdown(x,l,r);
if(lx<=mid) add(lc,l,mid);
else add(rc,mid+1,r);
pushup(x);
}
void cal(const int x,const int l,const int r)
{
if(rx<l||r<lx) return;
if(lx<=l&&r<=rx) { v+=seg[x].c; return; }
int mid=l+r>>1,lc=x<<1,rc=lc|1;
pushdown(x,l,r);
cal(lc,l,mid); cal(rc,mid+1,r);
}
struct D
{
int pos,x1,x2,i;
D(){}
D(const int _pos,const int _x1,const int _x2,const int _i){pos=_pos;x1=_x1;x2=_x2;i=_i;}
}a[maxk<<1]; int cnt;
inline bool cmp(const D x,const D y)
{
if(x.pos==y.pos) return x.i==y.i?x.x1>y.x1:x.i>y.i;
return x.pos<y.pos;
}
multiset<int>S;
multiset<int>::iterator it;
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=k;i++)
{
int x1,y1,x2,y2; scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
a[++cnt]=D(x1,y1,y2,1);
a[++cnt]=D(x2+1,y1,y2,-1);
}sort(a+1,a+cnt+1,cmp);
lx=rx=1; v=1ll; upd(1,1,m);
int pos=1; S.insert(0); S.insert(m+1);
while(pos<=cnt&&a[pos].pos==1)
{
S.insert(a[pos].x1); S.insert(a[pos].x2);
pos++;
}
for(int i=2;i<=n;i++)
{
while(pos<=cnt&&a[pos].pos==i)
{
if(a[pos].i==1)
{
it=S.upper_bound(a[pos].x2);
it--;
lx=(*it)+1,rx=a[pos].x2; v=0ll;
if(lx<=rx) cal(1,1,m); v%=Mod;
it=S.upper_bound(a[pos].x2);
if((*it)!=a[pos].x2+1) lx=rx=a[pos].x2+1,add(1,1,m);
lx=a[pos].x1,rx=a[pos].x2,v=0ll,upd(1,1,m);
S.insert(a[pos].x1); S.insert(a[pos].x2);
}
else
{
it=S.find(a[pos].x1);
S.erase(it);
it=S.find(a[pos].x2);
S.erase(it);
}
pos++;
}
}
it=S.lower_bound(m); it--;
lx=(*it)+1,rx=m,v=0;
if(lx<=rx) cal(1,1,m);
printf("%I64d\n",v%Mod);
return 0;
}