bzoj 3341: [Ceoi2013]adriatic 动态规划

题意

琪琪在大海上搜索涛涛,琪琪把大海分为2500*2500的网格,现在琪琪拥有N条小帆船,她可以在船之间移动,由于风向的原因,她只能从一条船移动到位于这条船严格左上方或严格右下方的船。对于每条帆船,琪琪想要知道从这条船跳到其他各条船的最小跳转次数和。
3 ≤ N ≤ 250 000

分析

咋一看还以为是KDtree。。。
一开始很直观的想法就是先把左上和右下两块搞掉,然后对于左下的一块,找到最左边和左下边的一个点来跳,这样就又把矩形变成了一个更小的矩形。但是对每个点这样切的话会T,那么只要记忆化一下即可。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=2505;
const int inf=1000000000;
const int M=2500;

int n,s[N][N],ur[N][N],dl[N][N],ul[N][N],dr[N][N],drd[N][N],drr[N][N],ulu[N][N],ull[N][N];
struct data{int x,y;}a[250005];

int read()
{
    int x=0,f=1;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;
}

int get_dl(int x,int y)
{
    if (x<1||x>M||y<1||y>M) return 0;
    if (dl[x][y]>-1) return dl[x][y];
    dl[x][y]=0;
    int d=min(drd[x][y+1],x),l=min(ull[x+1][y],y);
    return dl[x][y]=get_dl(d,l)+dr[x][1]-dr[x][y+1];
}

int get_ur(int x,int y)
{
    if (x<1||x>M||y<1||y>M) return 0;
    if (ur[x][y]>-1) return ur[x][y];
    ur[x][y]=0;
    int u=max(ulu[x][y-1],x),r=max(drr[x-1][y],y);
    return ur[x][y]=get_ur(u,r)+ul[x][M]-ul[x][y-1];
}

int main()
{
    n=read();
    for (int i=1;i<=n;i++) a[i].x=read(),a[i].y=read(),a[i].y=M-a[i].y+1,s[a[i].x][a[i].y]++;
    for (int i=0;i<=M+1;i++)
        for (int j=0;j<=M+1;j++)
        {
            ull[i][j]=drd[i][j]=inf;
            ulu[i][j]=drr[i][j]=-1;
            dl[i][j]=ur[i][j]=-1;
        }
    for (int i=M;i>=1;i--)
        for (int j=1;j<=M;j++)
        {
            ull[i][j]=min(ull[i][j-1],ull[i+1][j]);
            ulu[i][j]=max(ulu[i][j-1],ulu[i+1][j]);
            if (s[i][j]) ull[i][j]=min(ull[i][j],j),ulu[i][j]=max(ulu[i][j],i);
            ul[i][j]=ul[i][j-1]+ul[i+1][j]-ul[i+1][j-1]+s[i][j];
        }
    for (int i=1;i<=M;i++)
        for (int j=M;j>=1;j--)
        {
            drr[i][j]=max(drr[i][j+1],drr[i-1][j]);
            drd[i][j]=min(drd[i][j+1],drd[i-1][j]);
            if (s[i][j]) drr[i][j]=max(drr[i][j],j),drd[i][j]=min(drd[i][j],i);
            dr[i][j]=dr[i][j+1]+dr[i-1][j]-dr[i-1][j+1]+s[i][j];
        }
    for (int i=1;i<=n;i++)
    {
        int x=a[i].x,y=a[i].y;
        int ans=get_dl(x,y)+get_ur(x,y)+n-3;
        printf("%d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值