您的位置:首页 > 其它

bzoj5187 [Usaco2018 Jan]Sprinklers(数学+计数+前缀和)

2018-03-13 23:00 465 查看
这题真是神orz

首先我们发现原问题可以转化为:问你有多少对点对(x1,y1),(x2,y2)满足x1<x2,y1<y2x1<x2,y1<y2,每列可以选取的点在一个区间[low,top]中,我们还发现,随着x的递增,每一列的low是单调不增的,top也是单调不增的。(可以反证一下)

我们考虑从左到右枚举x2,每次计算出合法的(x1,y1,y2)三元组的个数加到答案里。合法就需要满足

x1<x2,y1<y2,lowx2<=y2<=topx2,lowx1<=y1<=topx1x1<x2,y1<y2,lowx2<=y2<=topx2,lowx1<=y1<=topx1

我们考虑到如果y2<lowx2y2<lowx2,则y1<y2<lowx2<=lowx1y1<y2<lowx2<=lowx1,(x1,y1)本身就是一个不合法的点,于是我们无需考虑lowx2<=y2这个条件lowx2<=y2这个条件。

我们考虑用所有的满足x1<x2,y1<y2<=topx2x1<x2,y1<y2<=topx2的三元组tot减去其中不合法的三元组,即y1<lowx1y1<lowx1的三元组bad。

我们显然有tot=top∗(top+1)/2∗x2tot=top∗(top+1)/2∗x2

对于bad我们拆开来计算:

对于y1<lowx2y1<lowx2的bad1=x2∗∑lowx2−1y1=0(top−y1)bad1=x2∗∑y1=0lowx2−1(top−y1)

对于lowx2<=y1<=lowx1lowx2<=y1<=lowx1的bad2,我们这样计算:

我们考虑处理出一个数组lst[i],表示不合法的(x1,i)有lft[i]个,即当x1< lft[i]时,(x1,i)均不合法。我们发现对于lowx2<=y1lowx2<=y1,lst[y1]是<=x2的,因此是与x2无关的,于是我们可以预处理出两个前缀和来帮助我们O(1)计算bad2.

总的复杂度就是O(n)O(n)的了。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 100010
#define mod 1000000007
inline char gc(){
static char buf[1<<16],*S,*T;
if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
return x*f;
}
int n,Y
,lft
,sum
,sum2
,top
;//Y[i]-->第i列的纵坐标
//lft[i]-->对于x<lft[i],(x,i)不合法,也即不合法的(x1,y1)有lft[y1]个
int main(){
//  freopen("a.in","r",stdin);
n=read();for(int i=1;i<=n;++i){int x=read();Y[x]=read();}
int low=n-1;
for(int i=0;i<n;++i)
while(Y[i]<=low) lft[low--]=i;
while(low>=0) lft[low--]=n;
for(int i=n-1;i>=0;--i) sum[i]=(sum[i+1]+lft[i])%mod;
for(int i=n-1;i>=0;--i) sum2[i]=(sum2[i+1]+(ll)lft[i]*(n-1-i))%mod;
for(int i=n-1;i>=0;--i) top[i]=max(top[i+1],Y[i]);
low=n-1;int ans=0;
for(int i=1;i<n;++i){
while(low>0&&lft[low-1]<=i) low--;
int all=(ll)top[i]*(top[i]+1)/2%mod*i%mod;
int bad1=(2LL*top[i]-low+1)*low/2%mod*i%mod;
int bad2=sum2[low]-sum2[top[i]+1]-(ll)(sum[low]-sum[top[i]+1])*(n-1-top[i])%mod;
bad2%=mod;bad1+=bad2;bad1%=mod;all-=bad1;all%=mod;ans+=all;ans%=mod;if(ans<0) ans+=mod;
}printf("%d\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: