当前位置: 代码迷 >> 综合 >> [bzoj5187][Usaco2018 Jan][数论]Sprinklers
  详细解决方案

[bzoj5187][Usaco2018 Jan][数论]Sprinklers

热度:12   发布时间:2023-12-19 05:16:03.0

Description

农夫约翰有一块很大的田,他正在考虑种甜玉米。经过对他农田的调查,FJ发现它形成了一个(N-1)×(N-1)的

正方形。西南角为坐标(0,0),东北角是(N-1,N-1)。在某些整数坐标的位置中有双头喷头,每一个都能够同
时喷洒水和肥料。一个在(i,j)处的双头喷头会将水洒在农田中所有在其东面且在其北面的区域,将肥料洒在农
田中所有在其南面且在其西面的区域。形式化地说,这个喷头将会将水洒在所有满足N≥x≥i和N≥y≥j的实数坐标
(x,y)上,会将肥料洒在所有满足0≤x≤i和0≤y≤j的实数坐标上农民约翰想在一些边与坐标轴平行的长方形农田
里种植甜玉米。然而,为了甜玉米的生长,矩形内的所有点都必须由双头喷头浇水和施肥。当然,矩形必须有正的
面积,否则农民约翰就不能在里面种植任何玉米!帮助农民约翰确定可以种植甜玉米的拥有正面积的矩形农田数。
由于这个数字可能很大,所以输出对为10^9 + 7取模

Input

第一行包含一个整数N,表示农场的大小(1≤N≤10^5)。

接下来的n行各包含两个由空格分隔的整数。这些整数中0≤i,j≤N-1,这表示有一个双头喷头位于(i,j)的位置。
保证每列都有一台喷头,每排正好有一台喷头。这也就是说,没有两个喷头有相同的x坐标或y坐标。

Output

输出包含一行,表示拥有正面积的合法矩形农田的个数,对10^9+7取模.

Sample Input

5

0 4

1 1

2 2

3 0

4 3

Sample Output

21

题解

比赛的最后半小时想到50分做法然而并没有细想就这么放过了式子题..
预处理能种小麦的点,发现总是组成一个多边形
这个多边形一定是阶梯状的…..画个图就清楚了就一些矩阵面积并
我们把答案的式子写出来

i=0n?1j=lw[i]up[i]k=lw[i]j?1i?lk ∑ i = 0 n ? 1 ∑ j = l w [ i ] u p [ i ] ∑ k = l w [ i ] j ? 1 i ? l k

其中up[i]表示第i列向上能到达的最高行,lw[i]表示向下能到达的最低行, lk l k 表示第k行向左最多能去到哪一列
画图最清晰了
一通乱化
i=0n?1j=lw[i]up[i]i?(j?lw[i])?k=lw[i]j?1lk ∑ i = 0 n ? 1 ∑ j = l w [ i ] u p [ i ] i ? ( j ? l w [ i ] ) ? ∑ k = l w [ i ] j ? 1 l k

i=0n?1i?(1+up[i]?lw[i])?(up[i]+lw[i])2?j=lw[i]+1up[i]k=lw[i]j?1lk ∑ i = 0 n ? 1 i ? ( 1 + u p [ i ] ? l w [ i ] ) ? ( u p [ i ] + l w [ i ] ) 2 ? ∑ j = l w [ i ] + 1 u p [ i ] ∑ k = l w [ i ] j ? 1 l k

化到这个地方前面的式子已经可以 O(1) O ( 1 ) 计算了,下来主要化后面的式子
设S[i]表示l数组的前缀和,pre[i]表示S数组的前缀和

j=lw[i]+1up[i]Sj?1?Slw[i]?1 ∑ j = l w [ i ] + 1 u p [ i ] S j ? 1 ? S l w [ i ] ? 1

preup[i]?1?prelw[i]?1?Slw[i]?1?(up[i]?lw[i]) p r e u p [ i ] ? 1 ? p r e l w [ i ] ? 1 ? S l w [ i ] ? 1 ? ( u p [ i ] ? l w [ i ] )

组合起来即为
i=0n?1i?(1+up[i]?lw[i])?(up[i]+lw[i])2?(preup[i]?1?prelw[i]?1?Slw[i]?1?(up[i]?lw[i])) ∑ i = 0 n ? 1 i ? ( 1 + u p [ i ] ? l w [ i ] ) ? ( u p [ i ] + l w [ i ] ) 2 ? ( p r e u p [ i ] ? 1 ? p r e l w [ i ] ? 1 ? S l w [ i ] ? 1 ? ( u p [ i ] ? l w [ i ] ) )

于是 O(n) O ( n ) 扫一遍就出答案了..

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#define LL long long
using namespace std;
inline int read()
{int f=1,x=0;char ch=getchar();while(ch<'0' || ch>'9'){
   if(ch=='-')f=-1;ch=getchar();}while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;
}
struct matrix{
   int x,y;}a[1000005];
bool cmp(matrix n1,matrix n2){
   return n1.x<n2.x;}
const LL mod=1e9+7;
LL pow_mod(LL a,int b)
{LL ret=1;while(b){if(b&1)ret=ret*a%mod;a=a*a%mod;b>>=1;}return ret;
}
int n;
LL lw[1000005],up[1000005],L[1000005];
LL S[1000005],pre[1000005];
int main()
{n=read();for(int i=1;i<=n;i++)a[i].x=read(),a[i].y=read();sort(a+1,a+1+n,cmp);memset(up,-1,sizeof(up));memset(lw,-1,sizeof(lw));memset(L,-1,sizeof(L));up[a[n].x]=a[n].y;int mx=a[n].y;for(int i=n-1;i>=1;i--)if(mx<a[i].y){up[a[i].x+1]=mx;up[a[i].x]=a[i].y;mx=a[i].y;}for(int i=n-1;i>=0;i--)if(up[i]==-1)up[i]=up[i+1];lw[a[1].x]=a[1].y;int mn=a[1].y;L[a[1].y]=a[1].x;int last=a[1].x;for(int i=2;i<=n;i++)if(mn>a[i].y){L[a[i].y]=a[i].x;lw[a[i].x-1]=mn;lw[a[i].x]=a[i].y;mn=a[i].y;last=a[i].x;}for(int i=0;i<n;i++)if(lw[i]==-1)lw[i]=lw[i-1];for(int i=0;i<n;i++)if(L[i]==-1)L[i]=L[i-1];
// printf("%d\n",L[546]);
/* for(int i=0;i<n;i++)printf("%d ",up[i]);puts("");for(int i=0;i<n;i++)printf("%d ",lw[i]);puts("");for(int i=0;i<n;i++)printf("%d ",L[i]);puts("");*///initfor(int i=0;i<n;i++)S[i]=(S[i-1]+L[i])%mod;for(int i=0;i<n;i++)pre[i]=(pre[i-1]+S[i])%mod;LL ans=0;for(int i=0;i<n;i++){LL cnt=(LL)((i*(up[i]-lw[i]+1))*(up[i]-lw[i])/2)%mod;LL tmp=pre[up[i]-1]-pre[lw[i]-1]-S[lw[i]-1]*(up[i]-lw[i])%mod;while(tmp<0)tmp+=mod;ans=(ans+cnt-tmp);while(ans<0)ans+=mod;ans%=mod;}printf("%lld\n",ans);return 0;
}