题解 P4184 【[USACO18JAN]Sprinklers P】
xtx1092515503 · · 题解
模拟赛2h上肝出此题,故发题解纪念一下
首先,我们先根据样例画一幅图:
其中,粉色格子是肥料和水全喷到的地方。
我们发现,对于一行里面,粉色格子的左界是在这一行上面的所有蓝点中,最靠左的那一个,而右界是在这一行下面的所有蓝点中,最靠右的那一个。
如果这不太清楚的话,我们再提供一组样例及它对应的图:
11
0 5
1 4
2 8
3 3
4 2
5 1
6 10
7 6
8 0
9 9
10 7
是不是明白了?
我们接下来考虑如何对于一行求答案。设每一行的左界是
则我们将第
这样预处理出来
代码:
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int n,up[100100],dw[100100],res;
pair<int,int>p[100100];
int main(){
scanf("%d",&n),dw[0]=0x3f3f3f3f;
for(int i=1;i<=n;i++)scanf("%d%d",&p[i].first,&p[i].second);
sort(p+1,p+n+1);
for(int i=n-1;i;i--)up[i]=max(up[i+1],p[i+1].second);
for(int i=1;i<n;i++)dw[i]=min(dw[i-1],p[i].second);
// for(int i=1;i<n;i++)printf("%d %d\n",up[i],dw[i]);
for(int i=1;i<n;i++)for(int j=i;j>=1&&dw[j]<up[i];j--)(res+=(1ll*(up[i]-dw[j])*(up[i]-dw[j]+1)/2)%mod)%=mod;
printf("%lld\n",res);
return 0;
}
然后,考虑优化。
当
具体地说,我们设两个值
则,当
因此就可以差分地在
代码:
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int n,up[100100],dw[100100],res;
pair<int,int>p[100100];
int main(){
scanf("%d",&n),dw[0]=up[0]=n;
for(int i=1;i<=n;i++)scanf("%d%d",&p[i].first,&p[i].second);
sort(p+1,p+n+1);
for(int i=n-1;i;i--)up[i]=max(up[i+1],p[i+1].second);
for(int i=1;i<n;i++)dw[i]=min(dw[i-1],p[i].second);
// for(int i=1;i<n;i++)printf("U:%d D:%d\n",up[i],dw[i]);
for(int i=1,j=1,k=0,l=0;i<n;i++){
if(up[i-1]>=dw[i])(k+=up[i-1]-dw[i])%=mod,(l+=(1ll*(up[i-1]-dw[i])*(up[i-1]-dw[i]+1)/2)%mod)%=mod;
for(int q=up[i-1];q>up[i];q--){
while(dw[j]==q)j++;
(l-=k)%=mod,(k-=(i-j+1))%=mod;
}
// printf("(%d,%d,%d,%d)\n",i,j,k,l);
(res+=l)%=mod;
}
printf("%lld\n",res);
return 0;
}