「NOIP2010」「LuoguP1514」引水入城

3 篇文章 0 订阅
1 篇文章 0 订阅

Description


在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠。该国的行政区划十分特殊,刚好构成一个 N×M 列的矩形,如上图所示,其中每个格子都代表一座城市,每座城市都有一个海拔高度。
这里写图片描述
为了使居民们都尽可能饮用到清澈的湖水,现在要在某些城市建造水利设施。水利设施有两种,分别为蓄水厂和输水站。蓄水厂的功能是利用水泵将湖泊中的水抽取到所在城市的蓄水池中。

因此,只有与湖泊毗邻的第 1 行的城市可以建造蓄水厂。而输水站的功能则是通过输水管线利用高度落差,将湖水从高处向低处输送。故一座城市能建造输水站的前提,是存在比它海拔更高且拥有公共边的相邻城市,已经建有水利设施。由于第 N 行的城市靠近沙漠,是该国的干旱区,所以要求其中的每座城市都建有水利设施。那么,这个要求能否满足呢?如果能,请计算最少建造几个蓄水厂;如果不能,求干旱区中不可能建有水利设施的城市数目。

Input


每行两个数,之间用一个空格隔开。输入的第一行是两个正整数 N,M ,表示矩形的规模。接下来 N 行,每行 M 个正整数,依次代表每座城市的海拔高度。

Output


两行。如果能满足要求,输出的第一行是整数 1 ,第二行是一个整数,代表最少建造几个蓄水厂;如果不能满足要求,输出的第一行是整数 0 ,第二行是一个整数,代表有几座干旱区中的城市不可能建有水利设施。

Sample Input1


2 5
9 1 5 4 3
8 7 6 1 2

Sample Output1


1
1

Sample Input2


3 6
8 4 5 6 4 4
7 3 4 3 3 3
3 2 2 1 1 2

Sample Output2


1
3

Hint


【样例1 说明】

只需要在海拔为 9 的那座城市中建造蓄水厂,即可满足要求。

【样例2 说明】
这里写图片描述
上图中,在 3 个粗线框出的城市中建造蓄水厂,可以满足要求。以这 3 个蓄水厂为源头在干旱区中建造的输水站分别用3 种颜色标出。当然,建造方法可能不唯一。

【数据范围】

这里写图片描述

题解


考虑数据范围,我们可以乱搞。
首先找一个湖泊边的城市,跑bfs,要求h [ temp ] < h [ now ] ,记录经过的点
然后在沙漠边上找被标记了的区间,如果有两个以上的区间被标记,那么无解(出现了不可逾越的小山包)。
重复m次,每次记得重置。

然后贪心做一遍区间覆盖。嗯。
/luogu迷之数据 第五个点卡了一波992ms的常

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define R register
int tu[507][507];
bool sf[507][507];
int q[250007][2];
int mx[5]={0,1,0,-1,0};
int my[5]={0,0,1,0,-1};
inline int read()
{
    char ch=getchar();
    int x=0;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
    return x;
}
struct emm{
    int l,r;
}a[50007];
int tot=0;
void con(int x,int y)
{
    a[++tot].l=x;
    a[tot].r=y;
    return;
}
bool cmp(emm qaq,emm qwq)
{
    return qaq.l==qwq.l?qaq.r<qwq.r:qaq.l<qwq.l;
}
bool b[507];
int main()
{
    //freopen("a.in","r",stdin);
    int n=read(),m=read();
    for(R int i=1;i<=n;++i)
    for(R int j=1;j<=m;++j)
    tu[i][j]=read();
    for(R int i=0;i<=n+1;++i)
    tu[i][0]=tu[i][m+1]=99999999;
    for(R int j=0;j<=m+1;++j)
    tu[0][j]=tu[n+1][j]=99999999;
    int flag=1;
    for(R int j=1;j<=m;++j)
    {
        memset(sf,0,sizeof(sf));
        int he=0,ta=1;
        q[1][0]=1;
        q[1][1]=j;
        sf[1][j]=1;
        do
        {
            he++;
            int x=q[he][0],y=q[he][1];
            for(R int c=1;c<=4;++c)
            {
                int u=x+mx[c],v=y+my[c];
                if(tu[x][y]>tu[u][v]&&!sf[u][v])
                {
                    q[++ta][0]=u;
                    q[ta][1]=v;
                    sf[u][v]=1;
                }
            }
        }while(he<ta);
        int l=0,flg=2;
        for(R int i=1;i<=m;++i)
        if(sf[n][i])
        {
            if(!l){l=i;flg--;}
            if(!sf[n][i+1]){con(l,i);l=0;}
        }
        if(!flg)flag--;
    }
    sort(a+1,a+tot+1,cmp);
    {
        for(R int c=1;c<=tot;++c)
        for(R int i=a[c].l;i<=a[c].r;++i)
        b[i]=1;
        int ans=0;
        for(R int i=1;i<=m;++i)
        if(!b[i])ans++;
        if(ans){cout<<0<<endl<<ans<<endl;return 0;}
    }
    int i=0,l=0,r=0;
    int ans=0;
    while(r<m)
    {
        if(a[++i].l<=l)r=max(r,a[i].r);
        else {ans++;l=r+1;r=a[i].r;}
    }
    cout<<1<<endl<<ans<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值