【题解】P6370 Ad-hoc 貌似没有算法

直接模拟的复杂度是 $O(nc)$,无法通过,考虑列数很少,维护每列开始放一个球下去掉落的路径,一个球一定会掉落到路径的末端,我们直接将球放在这里。

考虑这个球对所有起点开始的路径的影响,如果影响了,一定是堵上了某条路径末端,因为假设这个球堵住了某条路径中间的部分,那么它一定会随着这条路径继续滚下去,所以堵住的一定是末端,我们将被堵住的末端删除,从末端的上一步开始暴力模拟下去,重新求出这条路径新的样子即可。

复杂度证明:

考虑每条路径一定只会改变末端,路径的长度是 $O(c)$ 的,每一步只会使得路径的长度减少最多 $O(1)$,并重新扩展路径,时间复杂度是 $O(|\text{扩展长度}|)$ 的,所以每一步最多只会对每条路径贡献 $O(1)$ 的复杂度,共有 $c$ 条路径,时间复杂度 $O(rc + nc)$,空间 $O(rc)$。

一些想复杂了的做法:

维护每一层的 $to_i$,表示从这一层 $i$ 位置进入的球会从哪个位置出去,然后使用线段树维护区间 $to$ 的复合,时间复杂度 $O(rc + nc\log r)$。

还有更逆天的可以拿 lct 动态这个连向关系的森林,复杂度 $O((rc+n)\log rc)$。


/*
    所有的感受都将被铭记在心
        不必劳烦群星指引
*/ 
#include <bits/stdc++.h>
#define rep(i,x,y) for(auto i(x);i<=(y);++i)
#define Rep(i,x,y) for(auto i(x);i>=(y);--i)
signed main () {
    std :: ios :: sync_with_stdio (false); std :: cin.tie(0) , std :: cout.tie(0) ;
    int r , c; 
    std :: cin >> r >> c;
    std :: vector< std :: string > g(r) ;
    for (auto &ths : g) {
        std :: cin >> ths ;
    } 
    std :: vector < std :: vector < std :: pair <int, int> > >epos(c) ;
    auto check = [&] (int x,int y) {
        if (x < 0 || y < 0 || x >= r || y >= c) return -1 ;
        if (g[x][y] == 'X') return -1;
        return g[x][y] == 'O' ? 1 : 0 ; 
    } ;
    auto imple = [&check] (int x,int y) {
        std :: vector <std :: pair<int,int>> path ;
        if (check(x,y)) return path;
        while (1) {
            path.emplace_back (x , y) ;
            int t = check (x + 1 , y) ;
            if (t == 0) {
                ++ x ;
                continue ;
            }
            if (t == -1) {
                break ;
            }
            if (!check (x + 1 , y - 1) && !check (x , y - 1)) {
                -- y; ++ x;
                continue ;  
            }
            if (!check (x + 1 , y + 1) && !check (x , y + 1)) {
                ++ y; ++ x;
                continue ;
            }
            break ;
        }
        return path ;   
    } ;
    rep (i,0,c-1) {
        epos[i] = imple (0 , i); 
    }
    int q , i;
    std :: cin >> q ;
    while (q--) {
        std :: cin >> i ; -- i;
        int x = epos[i].back ( ).first , y = epos[i].back( ).second; 
        g[x][y] = 'O' ;
        rep (t,0,c - 1) {
            if(epos[t].back ( ) == std :: make_pair(x,y)) {
                epos[t].pop_back ( ) ;
                if (epos[t].size( )) {  
                    auto pth = imple (epos[t].back( ).first , epos[t].back ( ).second) ;
                    epos[t].pop_back  ( ) ;
                    for (const auto &v : pth) {
                        epos[t].push_back (v);
                    }
                }
            }
        }
    }
    for(const auto &ths : g)  {
        std :: cout << ths << '\n';
    }
}
posted @ 2023-11-13 19:30  寂静的海底  阅读(11)  评论(0编辑  收藏  举报  来源