[USACO 2020.1 Platinum][LOJ3246]Cave Paintings(bfs+树形dp)

题面

https://loj.ac/problem/3246

题解

注意到如果两个同在第i行的空格子,如果它们能够只通过原图的i~n行这部分实现连通,那么它们最终的状态一定是相同的。

考虑把所有这样的格子合并。也就是,我们将每一行的空格子分别染色,某一行中两个格子的颜色相同当且仅当这两个格子符合上述条件。石头格子没有颜色。

最下面一行的染色方案显然。而只需要经过bfs,就可以用第i+1行的染色方案推出第i行的染色方案。

染色结束后,我们可以把每一个二元组\((i,j)\)(表示所有第i行的第j种颜色的格子)视为一个点,然后连边,\((i_1,j_1)\)\((i_2,j_2)\)有一条单向边当且仅当\(i_2=i_1+1\),并且\({\exists}x{\in}(1,n)\),s.t.第\(i_1\)行第x个格子为空、颜色是\(j_1\),且第\(i_2\)行第x个格子为空、颜色是\(j_2\)

容易发现这样的话每个点只会有一条入边。连完边后,就形成了一棵森林,就可以使用下面的递推式计算点u的答案:

\[dp(u)=1+{\prod\limits_{v{\in}son[u]}}dp(v)\]

  • 其中1是u点被灌水的情况,那么其子树必须被灌水。否则,u的各子节点独立,可以使用乘法原理合并。

最终答案即为森林中所有的根节点的dp值之积。

时间复杂度为O(n)。

代码

#include<bits/stdc++.h>

using namespace std;

#define N 1000
#define mod 1000000007
#define rg register
#define ll long long

inline int read(){
    int s = 0,ww = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-')ww = -1;ch = getchar();}
    while('0' <= ch && ch <= '9'){s = 10 * s + ch - '0';ch = getchar();}
    return s * ww;
}

int n,m;

inline int id(int i,int j){ //将“第i行的第j种颜色”这个二元组编号压入一维 
    return (i - 1) * m + j;
}

char s[N+5][N+5];
bool vis[N*N+5]; 
int clr[N+5][N+5],cn[N+5],head[N*N+5],fa[N*N+5];//clr表示颜色(连通性),cn表示每一行的颜色个数 
int cnt;

struct edge{
    int next,des;
}e[N*N+5];

inline void addedge(int a,int b){
    cnt++;
    e[cnt].des = b;
    e[cnt].next = head[a];
    head[a] = cnt;
}

inline ll dp(int u){ //每一个u代表一个(i,j)的二元组,表示第i行的颜色j 
    ll cur = 1;
    vis[u] = 1;
    for(rg int i = head[u];i;i = e[i].next){
        int v = e[i].des;
        cur = cur * dp(v) % mod;
    }
    return (cur + 1) % mod;
}

struct Graph{ //用来转移clr的辅助图 
    int cnt;
    vector<int>link[3*N+5];
    int f[3*N+5];
    queue<int>q;
    
    inline void reset(){
        cnt = 0;
        for(rg int i = 1;i <= 3 * m;i++)link[i].resize(0);
        memset(f,0,sizeof(f));
    }
    
    inline void addedge(int a,int b){
        link[a].push_back(b);
        link[b].push_back(a);
    }
    
    inline bool bfs(int s){
        bool flag = 0;
        q.push(s);
        while(!q.empty()){
            int u = q.front();
            q.pop();
            for(rg int i = 0;i < link[u].size();i++){
                int v = link[u][i];
                if(!f[v]){
                    if(v <= m)flag = 1;
                    f[v] = f[u];
                    q.push(v);
                }
            }
        }
        return flag;
    }
    
    inline void calc(int i){
        reset();
        for(rg int j = 1;j < m;j++){
            if(s[i][j] == '.' && s[i][j+1] == '.')addedge(id(1,j),id(1,j+1));
            if(s[i+1][j] == '.' && s[i+1][j+1] == '.')addedge(id(2,j),id(2,j+1));
            if(s[i][j] == '.' && s[i+1][j] == '.')addedge(id(1,j),id(2,j));
            if(s[i+1][j] == '.')addedge(id(2,j),id(3,clr[i+1][j]));
        } //id(1,…)和(2,…)代表原图的第i,i+1行;如果原图第i+1行第j格颜色为c,那么辅助图中id(2,j)就要向id(3,c)连边
        for(rg int j = 1;j <= cn[i+1];j++){
            if(f[id(3,j)])continue;
            f[id(3,j)] = ++cn[i];
            if(!bfs(id(3,j)))cn[i]--; //第i+1行颜色为j的这一块不与第i行的任何块连通 
        }
        for(rg int j = 1;j < m;j++)if(f[id(1,j)])clr[i][j] = f[id(1,j)];
    }
}G;

int main(){
    freopen("cave.in","r",stdin);
    freopen("cave.out","w",stdout);
    n = read(),m = read();
    bool flag = 1;
    for(rg int i = 1;i <= n;i++)scanf("%s",s[i] + 1);
    for(rg int i = n - 1;i >= 2;i--){
        G.calc(i);
        for(rg int j = 2;j < m;j++)if(s[i][j] == '.' && s[i+1][j] == '.')
            fa[id(i+1,clr[i+1][j])] = id(i,clr[i][j]);
        for(rg int j = 1;j <= cn[i+1];j++)
            if(fa[id(i+1,j)])addedge(fa[id(i+1,j)],id(i+1,j));
        for(rg int j = 2;j < m;j++)if(s[i][j] == '.' && !clr[i][j]){
            if(s[i][j-1] == '.')clr[i][j] = clr[i][j-1];
            else clr[i][j] = ++cn[i];
        }
    }
    ll ans = 1;
    for(rg int i = 2;i < n;i++)
        for(rg int j = 2;j < m;j++){
            if(s[i][j] == '.' && !vis[id(i,clr[i][j])])ans = ans * dp(id(i,clr[i][j])) % mod;
        }
    cout << ans << endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/xh092113/p/12273848.html
今日推荐