模拟4题解 T3

T3奇袭


题目描述

由于各种原因,桐人现在被困在Under World(以下简称UW)中,而UW马上 要迎来最终的压力测试——魔界入侵。 

唯一一个神一般存在的Administrator被消灭了,靠原本的整合骑士的力量 是远远不够的。所以爱丽丝动员了UW全体人民,与整合骑士一起抗击魔族。

 在UW的驻地可以隐约看见魔族军队的大本营。整合骑士们打算在魔族入侵前 发动一次奇袭,袭击魔族大本营!

 为了降低风险,爱丽丝找到了你,一名优秀斥候,希望你能在奇袭前对魔族 大本营进行侦查,并计算出袭击的难度。 

经过侦查,你绘制出了魔族大本营的地图,然后发现,魔族大本营是一个N ×N的网格图,一共有N支军队驻扎在一些网格中(不会有两只军队驻扎在一起)。 

在大本营中,每有一个k×k(1≤k≤N)的子网格图包含恰好k支军队,我们袭 击的难度就会增加1点。

 现在请你根据绘制出的地图,告诉爱丽丝这次的袭击行动难度有多大。

输入

第一行,一个正整数N,表示网格图的大小以及军队数量。 

接下来N行,每行两个整数,Xi,Yi,表示第i支军队的坐标。

保证每一行和每一列都恰有一只军队,即每一个Xi和每一个Yi都是不一样 的。

输出

一行,一个整数表示袭击的难度。

样例输入

5
1 1
3 2
2 4
5 5
4 3

样例输出

10

提示


【样例解释】
显然,分别以(2,2)和(4,4)为左上,右下顶点的一个子网格图中有3支军队,
这为我们的难度贡献了1点。
类似的子网格图在原图中能找出10个。
【数据范围】
对于30%的数据,N ≤ 100
对于60%的数据,N ≤ 5000
对于100%的数据,N ≤ 50000


 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 #define Re register
 7 using namespace std;
 8 int read()
 9 {
10     int f=1,x=0;char ch=getchar();
11     while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
12     while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
13     return f*x;
14 }
15 const int maxn=50005;
16 int n,a[maxn],ans;
17 int lmax[maxn],lmin[maxn],rmax[maxn],rmin[maxn],t[2*maxn];
18 void work(int l,int r,int mid)
19 {
20     lmax[mid]=lmin[mid]=a[mid];
21     rmax[mid+1]=rmin[mid+1]=a[mid+1];
22     for(int i=mid-1;i>=l;i--)
23     {
24         lmax[i]=max(lmax[i+1],a[i]);
25         lmin[i]=min(lmin[i+1],a[i]);
26     }
27     for(int i=mid+2;i<=r;i++)
28     {
29         rmax[i]=max(rmax[i-1],a[i]);
30         rmin[i]=min(rmin[i-1],a[i]);
31     }
32     //both left
33     for(int i=l;i<=mid;i++)
34     {
35         int j=i+lmax[i]-lmin[i];
36         if(j>mid&&j<=r)
37             if(lmax[i]>rmax[j]&&lmin[i]<rmin[j])   //由于左右两个区间必定不会有相等的元素,所以不用考虑等号
38                 ans++;
39     }
40     //min is on left ,max is on right
41     int L=mid+1,R=mid+1;
42     while(L<=r&&lmax[l]>rmax[L])
43     {
44         t[rmax[L]-L+n]--;//走过的路径是不合法的
45         L++;                
46     }
47     while(R<=r&&lmin[l]<rmin[R])
48     {
49         t[rmax[R]-R+n]++;//走过的路径都是合法的
50         R++;                
51     }
52     for(int i=l;i<=mid;i++)//i从l向mid移动,lmin变大,lmax变小,使得LR能向左移动
53     {
54         while(L>mid+1&&lmax[i]<rmax[L-1])//当L==mid+1时,退出循环
55         {
56             L--;
57             t[rmax[L]-L+n]++;
58         }
59         while(R>mid+1&&lmin[i]>rmin[R-1])
60         {
61             R--;
62             t[rmax[R]-R+n]--;
63         }
64         if(t[lmin[i]-i+n]>0)
65             ans+=t[lmin[i]-i+n];
66     }
67     for(int i=mid+1;i<=r;i++)
68         t[rmax[i]-i+n]=0;
69 }
70 void divide(int l,int r)
71 {
72     if(l==r)
73     {
74         ans++;
75         return;
76     }
77     int mid=(l+r)>>1;
78     divide(l,mid);
79     divide(mid+1,r);
80     work(l,r,mid);
81     reverse(a+l,a+r+1);
82     if(((r-l)%2)==0) mid--;//1 2 3 4 5 交换后 5 4 3 2 1   仍然应该使123在一个区间所以 mid--;
83     work(l,r,mid);
84     reverse(a+l,a+r+1);
85 }
86 int main()
87 {
88     n=read();
89     for(int i=1;i<=n;i++)
90     {
91         int x,y;
92         x=read();y=read();
93         a[x]=y;
94     }
95     divide(1,n);
96     printf("%d",ans);
97 }
View Code

 这两种实现都正确,实质相同

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 #define Re register
 7 using namespace std;
 8 int read()
 9 {
10     int f=1,x=0;char ch=getchar();
11     while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
12     while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
13     return f*x;
14 }
15 const int maxn=50005;
16 int n,a[maxn],ans;
17 int lmax[maxn],lmin[maxn],rmax[maxn],rmin[maxn],t[2*maxn];
18 void work(int l,int r,int mid)
19 {
20     lmax[mid]=lmin[mid]=a[mid];
21     rmax[mid+1]=rmin[mid+1]=a[mid+1];
22     for(int i=mid-1;i>=l;i--)
23     {
24         lmax[i]=max(lmax[i+1],a[i]);
25         lmin[i]=min(lmin[i+1],a[i]);
26     }
27     for(int i=mid+2;i<=r;i++)
28     {
29         rmax[i]=max(rmax[i-1],a[i]);
30         rmin[i]=min(rmin[i-1],a[i]);
31     }
32     //both left
33     for(int i=l;i<=mid;i++)
34     {
35         int j=i+lmax[i]-lmin[i];
36         if(j>mid&&j<=r)
37             if(lmax[i]>rmax[j]&&lmin[i]<rmin[j])   //由于左右两个区间必定不会有相等的元素,所以不用考虑等号,下面同理
38                 ans++;
39     }
40     //min is on left ,max is on right
41     int L=mid+1,R=mid+1;
42     for(int i=mid;i>=l;i--)//i从mid向l移动,lmin变小,lmax变大,使得LR能向向右移动
43     {
44         while(L<=r&&lmax[i]>rmax[L])//属于不合法的部分
45         {
46             t[rmax[L]-L+n]--;
47             L++;
48         }
49         while(R<=r&&lmin[i]<rmin[R])//
50         {
51             t[rmax[R]-R+n]++;//合法的
52             R++;
53         }
54         if(t[lmin[i]-i+n]>0)
55             ans+=t[lmin[i]-i+n];
56     }
57     for(int i=mid+1;i<=r;i++)
58         t[rmax[i]-i+n]=0;
59 }
60 void divide(int l,int r)
61 {
62     if(l==r)
63     {
64         ans++;
65         return;
66     }
67     int mid=(l+r)>>1;
68     divide(l,mid);
69     divide(mid+1,r);
70     work(l,r,mid);
71     reverse(a+l,a+r+1);
72     if(((r-l)%2)==0) mid--;//1 2 3 4 5 交换后 5 4 3 2 1   仍然应该使123在一个区间所以 mid--;
73     work(l,r,mid);
74     reverse(a+l,a+r+1);
75 }
76 int main()
77 {
78     n=read();
79     for(int i=1;i<=n;i++)
80     {
81         int x,y;
82         x=read();y=read();
83         a[x]=y;
84     }
85     divide(1,n);
86     printf("%d",ans);
87 }
View Code

猜你喜欢

转载自www.cnblogs.com/casun547/p/11201102.html