模拟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 }
这两种实现都正确,实质相同
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 }
愿你在迷茫时,记起自己的珍贵。