[COCI2010-2011#7] POŠTAR 题解

· · 题解

题目传送门

一血 搬题+翻译者填坑

题意

Sol

看到 n \le 50 ,时限 4s ,感觉 O(n^5) 常数较好者能过。

如果暴力枚举最大值与最小值,再暴力跑图判断,则使复杂度成 O(n^6)

显然这样过不了。/kel

Q:直接枚举答案行不行呢?

A:不行,不确定确切最大最小,无法直接跑图。

那么肯定还是要枚举一个最大值或最小值。这个选最大还是最小啊,因人而异。

我写的是最小值。

这样再加上跑图的复杂度,你就已经有 O(n^4) 的复杂度了。

如何在 O(n) 以内的时间计算答案呢?

我们选择二分最大值

最大值可能个数有 n^2 个,二分复杂度即为 O(\log_2n^2) \to O(2\log_2n)

既然有了最大最小值,那么每次遍历跑图即可。

删去常数后 复杂度 O(n^4 \log_2 n)

可以跑过此题。(有点慢)

/*
***
还要继续努力
成为一名烤咕学家哦
***
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=55;
ll n,hs,h[N][N],a[N*N],vst[N][N],kx,ky,ans=0x3f3f3f3f,dx[8]={1,1,0,-1,-1,-1,0,1},dy[8]={0,-1,-1,-1,0,1,1,1};
char s[N][N];
template <typename T> void rd(T &x){
    ll fl=1;x=0;char c=getchar();
    for(;!isdigit(c);c=getchar())if(c=='-')fl=-fl;
    for(;isdigit(c);c=getchar())x=(x<<3)+(x<<1)+c-'0';
    x*=fl;
}
void wr(ll x){
    if(x<0)x=-x,putchar('-');
    if(x<10)putchar(x+'0');
    if(x>9)wr(x/10),putchar(x%10+'0');
}
void dfs(ll x,ll y,ll hl,ll hr){
    if(vst[x][y]) return;
    vst[x][y]=1;
    for(ll i=0;i<8;i++){
        if(x+dx[i]<0||x+dx[i]>=n||y+dy[i]<0||y+dy[i]>=n||h[x+dx[i]][y+dy[i]]<hl||h[x+dx[i]][y+dy[i]]>hr) continue;
        dfs(x+dx[i],y+dy[i],hl,hr);
    }
}
bool ok(ll hl,ll hr){
    memset(vst,0,sizeof(vst));
    if(h[kx][ky]<hl||h[kx][ky]>hr) return 0;
    dfs(kx,ky,hl,hr);
    for(ll i=0;i<n;i++)
        for(ll j=0;j<n;j++)
            if(s[i][j]=='K'&&!vst[i][j]) return 0;
    return 1;
}
int main(){
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);
    rd(n);
    for(ll i=0;i<n;i++){
        scanf("%s",s[i]);
        for(ll j=0;j<n;j++) if(s[i][j]=='P') kx=i,ky=j;
    }
    for(ll i=0;i<n;i++)
        for(ll j=0;j<n;j++){rd(h[i][j]);a[hs++]=h[i][j];}
    sort(a,a+hs);
    hs=unique(a,a+hs)-a;
    for(ll i=0;i<hs;i++){
        ll l=i,r=hs-1;
        while(l<=r){
            ll mid=l+((r-l)>>1);
            if(ok(a[i],a[mid])) r=mid-1;
            else l=mid+1;
        }
        if(ok(a[i],a[l])) ans=min(ans,a[l]-a[i]);
    }
    wr(ans);puts("");
    return 0;
}

UPD 更新了复杂度