AtCoder AGC028-F:Reachable Cells

Posted turboboost

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AtCoder AGC028-F:Reachable Cells相关的知识,希望对你有一定的参考价值。

停更一个月后的第一篇文章。

题意:

给定一个(N)(N)列的迷宫,每一个格子要么是障碍,要么是空地。每一块空地写着一个数码。在迷宫中,每一步只允许向右、向下走,且只能经过空地。

对于每两个连通(从一个可到达另一个)的格子,求出它们数码的乘积。问所有这种乘积的和。

(1 leq N leq 500)

思路:

容易把到达关系建成一张DAG,但是DAG后继数问题,众所周知只有(O(|E||V|))做法,于是换思路。

我们猜测,从一个格子出发,可以达到的点集“大约”是一个凸包的形状。

而这个猜想也“大约”是对的,然而要使其完全正确,还有很长的路要走。

第一步

4177143673
7#########
5#1716155#
6#4#####5#
2#3#597#6#
6#9#8#3#5#
5#2#899#9#
1#6#####6#
6#5359657#
5#########

以上是样例4的网格。

代码:

#include <bits/stdc++.h>
#pragma GCC optimize(3)
using namespace std;
#define iinf 2000000000
#define linf 1000000000000000000LL
#define ulinf 10000000000000000000ull
#define MOD1 1000000007LL
#define mpr make_pair
typedef long long LL;
typedef unsigned long long ULL;
typedef unsigned long UL;
typedef unsigned short US;
typedef pair < int , int > pii;
clock_t __stt;
inline void TStart(){__stt=clock();}
inline void TReport(){printf("
Taken Time : %.3lf sec
",(double)(clock()-__stt)/CLOCKS_PER_SEC);}
template < typename T > T MIN(T a,T b){return a<b?a:b;}
template < typename T > T MAX(T a,T b){return a>b?a:b;}
template < typename T > T ABS(T a){return a>0?a:(-a);}
template < typename T > void UMIN(T &a,T b){if(b<a) a=b;}
template < typename T > void UMAX(T &a,T b){if(b>a) a=b;}
int n,g[505][505],s[505][505],mx[505];
bool e[505][505];
LL res;
int readchar(){
    char c=getchar();
    while(c==‘ ‘ || c==‘
‘) c=getchar();
    if(c==‘#‘) return 0;
    return c-‘0‘;
}
namespace DSU{
    int fa[250005],rk[250005];
    void init(){
        int i;
        memset(rk,0,sizeof(rk));
        for(i=0;i<=n*n;++i) fa[i]=i;
    }
    int ancestor(int x){
        if(fa[x]!=x) fa[x]=ancestor(fa[x]);
        return fa[x];
    }
    void unite(int u,int v){
        u=ancestor(u);
        v=ancestor(v);
        if(rk[u]<rk[v])
            fa[u]=v;
        else if(rk[u]>rk[v])
            fa[v]=u;
        else{
            fa[u]=v;
            ++rk[v];
        }
    }
    bool con(int u,int v){
        return ancestor(u)==ancestor(v);
    }
};
void add(int x,int y){
    e[x][y]=1;
    if(e[x-1][y]) DSU::unite(x*n+y,(x-1)*n+y);
    if(e[x][y-1]) DSU::unite(x*n+y-1,x*n+y);
    if(e[x+1][y]) DSU::unite(x*n+y,(x+1)*n+y);
    if(e[x][y+1]) DSU::unite(x*n+y+1,x*n+y);
    if(x<n-1 && g[x+1][y] && !e[x+1][y]) add(x+1,y);
    if(y<n-1 && g[x][y+1] && !e[x][y+1]) add(x,y+1);
}
int getlower(int x,int y){
    int cx=x,cy=y,ret=(y?s[x][y-1]:0);
    mx[y]=x;
    while(1){
        while(1){
            if(cx+1<n && e[cx+1][cy]){
                ++cx;
                mx[y]=cx;
                ret+=(cy?s[cx][cy-1]:0);
            }
            else if(cy+1<n && e[cx][cy+1]){
                ++cy;
            }
            else break;
        }
        bool found=0;
        while(cy+1<n){
            ++cy;
            if(e[cx][cy] && DSU::con(cx*n+cy,x*n+y)){
                found=1;
                break;
            }
            else if(e[cx][cy]) break;
        }
        if(!found) break;
    }
    return ret;
}
int getupper(int x,int y){
    int cx=x,cy=y,ret=0;
    while(1){
        while(1){
            if(cy+1<n && e[cx][cy+1]){
                ++cy;
            }
            else if(cx+1<n && e[cx+1][cy]){
                ret+=s[cx][cy];
                ++cx;
            }
            else break;
        }
        bool found=0;
        while(cx<n-1){
            ret+=s[cx][cy];
            ++cx;
            if(cx>mx[y]) break;
            if(e[cx][cy] && DSU::con(cx*n+cy,x*n+y)){
                found=1;
                break;
            }
            else if(e[cx][cy]) break;
        }
        if(!found || cx>mx[y]) break;
    }
    if(cx<=mx[y]) ret+=s[cx][cy];
    return ret;
}
void solveline(int x){
    int i,j,k;
    memcpy(s,g,sizeof(g));
    for(i=0;i<n;++i){
        for(j=1;j<n;++j){
            s[i][j]+=s[i][j-1];
        }
    }
    DSU::init();
    for(i=x;i<n;++i) memset(e[i],0,sizeof(e[i]));
    for(i=0;i<n;++i){
        if(!g[x][i]) continue;
        add(x,i);
        res-=(LL)g[x][i]*(LL)getlower(x,i);
    }
    DSU::init();
    for(i=x;i<n;++i) memset(e[i],0,sizeof(e[i]));
    for(i=n-1;i>=0;--i){
        if(!g[x][i]) continue;
        add(x,i);
        res+=(LL)g[x][i]*(LL)(getupper(x,i)-g[x][i]);
    }
}
void del(int x,int y){
    if((!x || !g[x-1][y]) && (!y || !g[x][y-1])){
        g[x][y]=0;
        if(x<n-1 && g[x+1][y]) del(x+1,y);
        if(y<n-1 && g[x][y+1]) del(x,y+1);
    }
}
int main(){
    // inputting start
    // 数据结构记得初始化! n,m别写反!
    int i,j,k;
    scanf("%d",&n);
    for(i=0;i<n;++i){
        for(j=0;j<n;++j){
            g[i][j]=readchar();
        }
    }
    #ifdef LOCAL
        TStart();
    #endif
    // calculation start
    // 数据结构记得初始化! n,m别写反!
    for(i=0;i<n;++i){
        for(j=0;j<n;++j){
            e[i][j]=(!!g[i][j]);
        }
    }
    for(i=n-1;i>=0;--i){
        solveline(i);
        for(j=0;j<n;++j){
            if(g[i][j]) del(i,j);
        }
    }
    printf("%lld
",res);
    #ifdef LOCAL
        TReport();
    #endif
    return 0;
}









以上是关于AtCoder AGC028-F:Reachable Cells的主要内容,如果未能解决你的问题,请参考以下文章

AtCoder AGC036C GP 2 (组合计数)

AtCoder AGC033F Adding Edges (图论)

AtCoder AGC032D Rotation Sort (DP)

AtCoder AGC029E Wandering TKHS

AtCoder AGC030B Tree Burning

AtCoder AGC038 C-LCMs 题解