| 分治-奇袭raid

3.奇袭

(raid.cpp\c\pas)

【问题描述】

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

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

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

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

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

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

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

【输入格式】

第一行,一个正整数N,表示网格图的大小以及军队数量。接下来N行,每行两个整数,Xi,Yi,表示第i支军队的坐标。

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

【输出格式】

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

【输入输出样例】

raid.in

5

1 1

3 2

2 4

5 5

4 3

 raid.out

10

【样例解释】

显然,分别以(2,2)和(4,4)为左上,右下顶点的一个子网格图中有3支军队,这为我们的难度贡献了1点。

类似的子网格图在原图中能找出10个。【数据范围】

对于30%的数据,N ≤ 100

对于60%的数据,N ≤ 5000 对于100%的数据,N ≤ 50000

题目的关键点:

1)每一行和每一列都恰有一只军队。因此合法矩形只要满足 存在军队的点的横坐标的最值之差 = 存在军队的点的纵坐标最值之差 即可。

换言之,若以x作为y的下标,即存在军队的点(x,y)等价于(x,map[x]),则合法矩形满足 max(map[x])-min(map[x]) = right - left

其中 x∈(left,right)

2)因为 max(map[x])-min(map[x]) = right - left = 边长d,所以当最值之差确定,则边长确定。

3)n的范围决定了AC解法不能是O(n²)的,因此无法同时枚举起点和矩形边长,由此排除dp

......我知道该题真的很像dp(○´?д?)?

对于纵坐标在(l,r)之间的地图,合法矩形的数目 = 只覆盖左侧的矩形 + 只覆盖右侧的矩形 + 同时覆盖左右的矩形

前两者用递归统计答案,因此每一个区间只用统计同时覆盖左右的矩形即可

同时覆盖左右的矩形,它的区间最值分布可能是:

  • 同在矩形左侧
  • 最小值在矩形左侧,最大值在矩形右侧
  • 同在矩形右侧
  • 最小值在矩形右侧,最大值在矩形左侧

在地图(l,r)枚举矩形的边界i

由于矩形是连续的而不能割裂,因此维护最值是矩形的边界到中点的最值

如max[i]维护的是区间[i,mid]的最大值(l<=i<=mid)

max[i]维护的是区间[mid+1,i]的最大值(mid<i<=r)

1)同在矩形左侧

设左边界为i

矩形边长d = max[i,mid] - min[i,mid]

矩形右边界 j = i + d = i + max[i,mid] - min[i,mid]

  • ∵同时覆盖左右 ∴j >= mid 且 j <= r
  • ∵最小值在左侧 ∴min(mid,j] > min[i,mid]
  • ∵最大值也在左侧 ∴max(mid,i] > max[j,mid]

2)最小值在矩形左侧,最大值在矩形右侧

max(map[mid,x])-min(map[x,mid]) = right - left

移项可得 max(map[mid,x])-right = min(map[x,mid]) - left

因为此处枚举的是左边界i,因此 min(map[x,mid])-left = min(map[i,mid])- i 只与当前i有关

  • ∵同时覆盖左右 ∴j >= mid 且 j <= r
  • ∵最小值在左侧 ∴min(mid,j] > min[i,mid]
  • ∵最大值在右侧 ∴max(mid,i] < max[j,mid]

而 max(map[mid,x]) 递增,min(map[mid,x])递减

因此可以用桶排序筛选合法的右边界

int m=(l+r)/2;
    mmax[m]=mmin[m]=map[m];
    mmax[m+1]=mmin[m+1]=map[m+1];
    /* mmin[i]指i到mid这段区间的最值 */
    for(int i=m-1;i>=l;i--) {mmin[i]=min(mmin[i+1],map[i]); mmax[i]=max(mmax[i+1],map[i]);}
    for(int i=m+2;i<=r;i++) {mmin[i]=min(mmin[i-1],map[i]); mmax[i]=max(mmax[i-1],map[i]);}
    int z1=m+1,z2=m+1;
    for(int i=m;i>=l;i--)
    {
        int j=mmax[i]-mmin[i]+i;
        /* 最值同在左侧 */
        if(j>m&&j<=r&&mmax[j]<mmax[i]&&mmin[j]>mmin[i]) ans++;
        /* 最大值在右侧 且满足最小值在左侧 */
        /* 当mmax[k1]-k1=mmin[k2]-k2时矩形(k2,mmin[k2],k1,mmax[k1])合法 */
        while(z2<=r&&mmin[z2]>=mmin[i]) {sum[mmax[z2]-z2+MAX]++;z2++;}
        while(z1<=r&&mmax[z1]<=mmax[i]) {sum[mmax[z1]-z1+MAX]--;z1++;}
        ans+=max(sum[mmin[i]-i+MAX],0);
     }     

右边界的处理同理

     z1=m;z2=m;
    for(int i=l;i<=r;i++) sum[mmax[i]-i+MAX]=0;
    for(int i=m+1;i<=r;i++)
    {
        int j=i-mmax[i]+mmin[i];
        if(j>=l&&j<=m&&mmax[j]<mmax[i]&&mmin[j]>mmin[i]) ans++;
        while(z2>=l&&mmin[z2]>=mmin[i]) {sum[mmax[z2]+z2+MAX]++;z2--;}
        while(z1>=l&&mmax[z1]<=mmax[i]) {sum[mmax[z1]+z1+MAX]--;z1--;}
        ans+=max(sum[mmin[i]+i+MAX],0);
    }
    for(int i=l;i<=r;i++) sum[mmax[i]+i+MAX]=0;

完整的AC代码

#include<cstdio>
#include<algorithm>
using namespace std;
const int MAX=50000;
int n;
int map[50001],mmax[50001],mmin[50001];
int sum[50001+MAX];
int ans=0;
void work(int l,int r)
{
    if(l==r) return;
    int m=(l+r)/2;
    mmax[m]=mmin[m]=map[m];
    mmax[m+1]=mmin[m+1]=map[m+1];
    /* mmin[i]指i到mid这段区间的最值 */
    for(int i=m-1;i>=l;i--) {mmin[i]=min(mmin[i+1],map[i]); mmax[i]=max(mmax[i+1],map[i]);}
    for(int i=m+2;i<=r;i++) {mmin[i]=min(mmin[i-1],map[i]); mmax[i]=max(mmax[i-1],map[i]);}
    int z1=m+1,z2=m+1;
    for(int i=m;i>=l;i--)
    {
        int j=mmax[i]-mmin[i]+i;
        /* 最值同在左侧 */
        if(j>m&&j<=r&&mmax[j]<mmax[i]&&mmin[j]>mmin[i]) ans++;
        /* 最大值在右侧 且满足最小值在左侧 */
        /* 前缀和基于mmax[k1]-k1=mmin[k2]-k2时矩形(k2,mmin[k2],k1,mmax[k1])合法 */
        while(z2<=r&&mmin[z2]>=mmin[i]) {sum[mmax[z2]-z2+MAX]++;z2++;}
        while(z1<=r&&mmax[z1]<=mmax[i]) {sum[mmax[z1]-z1+MAX]--;z1++;}
        ans+=max(sum[mmin[i]-i+MAX],0);
     }
     z1=m;z2=m;
    for(int i=l;i<=r;i++) sum[mmax[i]-i+MAX]=0;
    for(int i=m+1;i<=r;i++)
    {
        int j=i-mmax[i]+mmin[i];
        if(j>=l&&j<=m&&mmax[j]<mmax[i]&&mmin[j]>mmin[i]) ans++;
        while(z2>=l&&mmin[z2]>=mmin[i]) {sum[mmax[z2]+z2+MAX]++;z2--;}
        while(z1>=l&&mmax[z1]<=mmax[i]) {sum[mmax[z1]+z1+MAX]--;z1--;}
        ans+=max(sum[mmin[i]+i+MAX],0);
    }
    for(int i=l;i<=r;i++) sum[mmax[i]+i+MAX]=0;
    work(l,m);
    work(m+1,r);
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int a,b;t
        scanf("%d%d",&a,&b);
        map[a]=b;
    }
    work(1,n);
    printf("%d",ans+n);
}

HYX说可以用 分块+单调栈 做,不过还没有看分块的我(○´?д?)?

那么看了分块以后就回来写这道题吧咕咕咕

原文地址:https://www.cnblogs.com/orange-/p/10801533.html

时间: 2024-11-14 12:17:35

| 分治-奇袭raid的相关文章

Noip模拟考试6:解题报告

Peter喜欢玩数组.NOIP这天,他从Jason手里得到了大小为n的一个正整数数组.Peter求出了这个数组的所有子段和,并将这n(n+1)/2个数降序排序,他想知道前k个数是什么. 不难想到,从最大字段和向下更新. 用set实现 介绍一下set:用法与priority_queue基本相同,区别是,set有自动去重,而priority_queue将所有元素放入. 然后通过三元组,分别记录权值,左端与右端. #include<cstdio> #include<algorithm>

解题报告 『Raid(分治)』

原题地址 大概翻译一下题意: 在与联邦的战争接连失败之后,帝国方面撤退到了最后的据点.凭借着强大的防御系统,帝国军击退了联邦的六波进攻.经过几天不眠不休的思考,Arthur,联邦统帅,注意到防御系统的唯一弱点是它的能源供应.该系统由n个核电站进行充电,任何一个核电站的故障都会导致系统失效. 将军很快就发动了一次突袭,突袭者是准备潜行进入要塞的N名特工.不幸的是,由于帝国空军的攻击,他们未能按预期的位置着陆.作为一名经验丰富的将军,Arthur很快意识到他需要重新安排计划.他现在想知道的第一件事是

$Poj3714/AcWing\ Raid$ 分治/平面最近点对

$AcWing$ $Sol$ 平面最近点对板子题,注意要求的是两种不同的点之间的距离. $Code$ #include<bits/stdc++.h> #define il inline #define Rg register #define go(i,a,b) for(Rg int i=a;i<=b;++i) #define yes(i,a,b) for(Rg int i=a;i>=b;--i) #define mem(a,b) memset(a,b,sizeof(a)) #def

poj3714 Raid(分治求平面最近点对)

题目链接:https://vjudge.net/problem/POJ-3714 题意:给定两个点集,求最短距离. 思路:在平面最近点对基础上加了个条件,我么不访用f做标记,集合1的f为1,集合2的f为-1,那么求两个点的距离时,如果a.f*b.f=-1时计算距离,否则乘积为1的话返回inf.其它就和hdoj1007一样了. AC代码: #include<cstdio> #include<algorithm> #include<cmath> #include<cs

P3714 Raid

Raid Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 10625   Accepted: 3192 Description After successive failures in the battles against the Union, the Empire retreated to its last stronghold. Depending on its powerful defense system, th

[SinGuLaRiTy] 分治题目复习

[SInGuLaRiTy-1025] Copyrights (c) SinGuLaRiTy 2017. All Rights Reserved. [POJ 1905] 棍的扩张 (Expanding Rods) 题目描述 已知一根长为L的细棍被加热了n摄氏度,那么其新的长度为L'=(1+n*C)*L.中间的C是热膨胀系数.当一根细棍被夹在两面墙中间然后被加热,它会膨胀,其形状会变成一个弧,而原来的细棍(加热前的细棍)就是这个弧所对的弦.你的任务是计算出弧的中点与弦的中点的距离. 输入 包含多组数

[JZOJ4687]奇袭

[JZOJ4687]奇袭 题目 由于各种原因,桐人现在被困在Under World(以下简称UW)中,而UW马上要迎来最终的压力测试——魔界入侵. 唯一一个神一般存在的Administrator被消灭了,靠原本的整合骑士的力量是远远不够的.所以爱丽丝动员了UW全体人民,与整合骑士一起抗击魔族. 在UW的驻地可以隐约看见魔族军队的大本营.整合骑士们打算在魔族入侵前发动一次奇袭,袭击魔族大本营! 为了降低风险,爱丽丝找到了你,一名优秀斥候,希望你能在奇袭前对魔族大本营进行侦查,并计算出袭击的难度. 

【NOIP2016提高A组8.12】奇袭

题目 由于各种原因,桐人现在被困在Under World(以下简称UW)中,而UW马上要迎来最终的压力测试--魔界入侵. 唯一一个神一般存在的Administrator被消灭了,靠原本的整合骑士的力量是远远不够的.所以爱丽丝动员了UW全体人民,与整合骑士一起抗击魔族. 在UW的驻地可以隐约看见魔族军队的大本营.整合骑士们打算在魔族入侵前发动一次奇袭,袭击魔族大本营! 为了降低风险,爱丽丝找到了你,一名优秀斥候,希望你能在奇袭前对魔族大本营进行侦查,并计算出袭击的难度. 经过侦查,你绘制出了魔族大

软件raid 5

软件raid 5的实现 RAID 5 是一种存储性能.数据安全和存储成本兼顾的存储解决方案. RAID 5可以理解为是RAID 0和RAID 1的折中方案.RAID 5可以为系统提供数据安全保障,但保障程度要比Mirror低而磁盘空间利用率要比Mirror高.RAID 5具有和RAID 0相近似的数据读取速度,只是多了一个奇偶校验信息,写入数据的速度比对单个磁盘进行写入操作稍慢.同时由于多个数据对应一个奇偶校验信息,RAID 5的磁盘空间利用率要比RAID 1高,存储成本相对较低,是目前运用较多