1 条题解
-
0
挺好的题。
首先,没有被任何矩形覆盖的各自随便决定放或不放,快速幂最后乘一下就好了。
我们不难发现若一个矩形被另一个矩形所包含,那么另一个矩形的限制就没有意义了,也就是横坐标纵坐标同时大于另一矩形的矩形我们可以直接忽略。这样我们就把所有矩形转化为了横坐标递增,纵坐标递减的类型,如果这里看不懂可以画一画样例。
接下来不难发现,一个格子若被多个矩形包含,则一定会被包含在一段连续的矩形当中,因为如果一个矩形不包含它,那么一定是纵坐标小了或横坐标小了,然而我们有单调性,越左越右肯定会越变越差,所以是连续的。
接下来我们可以考虑动态规划了,我们考虑状态为只考虑前 个限制的方案数。
考虑转移,我们有两种选择,一种是根本不在这个矩形中放,这种直接由前一个状态转移来即可,另一种是放了,如果放在与其他矩形相交的地方了,我们肯定要求所有包含这一点矩形什么都不能放。
我们之前发现的性质是与其相交的矩形一定是连续的,我们不妨钦定与其相交的矩形是从 到 的所有矩形,而其他矩形不能包含这个点,这样我们对这样的点数计数,乘到 的状态上,也就达成了 到 什么都不放的诉求。
我们已经有一个时间复杂度平方的算法了,我们更进一步,发现这个点数计数我们既有关于转移点的信息,又有关于被转移点的信息,这太讨厌了,但是仔细看就会发现,被转移点只和纵坐标有关,转移点只和横坐标有关,我们不妨把纵坐标提出来,然后前缀和维护动态规划值和横坐标的乘积,具体的:
我们这题就愉快的通过了。
#include<bits/stdc++.h> using namespace std; namespace MyGO{ #define int long long bool NagasakiSoyo; const int INF=0x3f3f3f3f3f3f3f3f; const int mod=1e9+7; struct Sqr{ int r,c; } a[210000],b[210000]; int f[210000]; int qpow(int x,int y){ int res=1; while(y){ if(y&1) res=res*x%mod; x=x*x%mod;y>>=1; } return res; } bool ChihayaAnon; void main(){ cerr<<((&NagasakiSoyo)-(&ChihayaAnon))/1048576.0<<'\n'; // freopen("data.in","r",stdin); // freopen("data.out","w",stdout); int n,m;cin>>n>>m; for(int i=1;i<=n;i++) cin>>a[i].r>>a[i].c; sort(a+1,a+n+1,[&](Sqr X,Sqr Y){ return X.r<Y.r; }); deque<int> s; for(int i=1;i<=n;i++){ while((not s.empty()) and (a[s.back()].c<a[i].c)) s.pop_back(); s.push_back(i); } n=0;int K=0; while(not s.empty()){ b[++n]=a[s.front()]; s.pop_front(); K=K+(b[n].r-b[n-1].r)*(m-b[n].c); } K=K+(m-b[n].r)*m; K=qpow(2,K); int sum=0;f[0]=1;sum=sum+b[1].r; for(int i=1;i<=n;i++){ f[i]=f[i-1]+sum*(b[i].c-b[i+1].c)%mod;f[i]%=mod; sum=sum+f[i]*(b[i+1].r-b[i].r)%mod;sum%=mod; } cout<<f[n]*K%mod<<'\n'; cerr<<1.0*clock()/CLOCKS_PER_SEC*1000.0<<'\n'; } #undef int } int main(){ ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); MyGO::main(); return 0; }
- 1
信息
- ID
- 9648
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者