文章目录

题解:CF2147B Multiple Construction

由 SunJude 发布

赛时这个题和 E 卡了我八百年,怄火怄火怄火。

来个不需要脑电波构造的方法。

如何用奇怪的方式撞到通解。

Solution

首先从剩余系的角度入手:把每个下标 $\bmod x$,划分成 $x$ 个同余类,这样想给 $x$ 选两个位置只需要在某个同余类里找两个空位即可。

有一个显然错误的暴力思路是按 $x$ 从小到大暴力放。具体地,对于每个 $x$,用并查集维护空位 $p$,每次找到一个空位就暴力跳,如果有 $p$ 和 $p + kx$ 都是空位,就把这两个位置填上 $x$,如果没有就继续看下一个空位。

这个做法随便举个例子比如 $n = 3$ 就能轻松 hack。原因是,我们没办法保证处理到 $x$ 时一定有一个同余类有 $\geq 2 $ 个空位。

但是我们可以按 $x$ 从大到小放!这样当处理到 $x$ 的时候前面已经占了 $2(n - x)$ 个位置,还剩 $2x$ 个空位,抽屉原理可得,至少有一个同余类 $\geq 2$ 个空位,所以正确性是对的。

这时候有一个很好玩的事情:我们不难发现,这个做法构造出来的其实和官解那个 $n, n - 1, \cdots, 1, n, 1, 2, n - 1$ 是一样的,所以其实每个 $x$ 只会跳 $O(1)$ 次,因此复杂度是 $O(n\alpha (n))$。

Code

// Problem: B. Multiple Construction
// Contest: Codeforces - Codeforces Global Round 29 (Div. 1 + Div. 2)
// URL: https://codeforces.com/contest/2147/problem/B
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long 
#define pii pair<int,int>
#define pb push_back
#define endl '\n'
#define rep(i, a, b) for(int (i) = (a); (i) <= (b); (i) ++)
#define per(i, a, b) for(int (i) = (a); (i) >= (b); (i) --)
#define ls x << 1
#define rs x << 1 | 1

using namespace std;

const int maxn = 4e5 + 5 ;

int n, ans[maxn] ;
int m ;
bool vis[maxn] ;
struct dsu {
    int f[maxn], g[maxn] ;
    void init() {
        rep(i, 1, m + 1) f[i] = i ;
    }
    int fnd(int x) {
        if(x == f[x]) return x ;
        f[x] = fnd(f[x]) ;
        return f[x] ;
    }
    void add(int x) {
        f[x] = fnd(x + 1) ;
    }
} d ;

void solve(){
    cin >> n ;
    m = n * 2 ;
    d.init() ;
    rep(i, 1, m) {
        ans[i] = vis[i] = 0 ;
    } 
    per(x, n, 1) {
        int p = d.fnd(1) ;
        while(p <= m) {
            int q = p + x ;
            while(q <= m && vis[q]) q += x ;
            if(q <= m) {
                ans[p] = ans[q] = x ;
                vis[p] = vis[q] = 1 ;
                d.add(p) ; d.add(q) ;
                break ;
            }
            else p = d.fnd(p + 1) ;
        }
    }
    rep(i, 1, m) {
        cout << ans[i] << ' ' ;
    } 
    cout << endl ;
    return ;
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int T = 1 ; 
    cin >> T ;
    while(T -- ){
        solve() ;
    }
    return 0 ;
} 

暂无评论

发表评论