Luogu P14972 『GTOI - 2C』Fliping 题解 [ 绿 ] [ 随机化 ] [ 构造 ]

Fliping

猎奇随机化史题。

一种想法是依次将 \(n\sim 1\) 归位,但是由于不能翻转长度为 \(2\) 的区间,所以若遇到 \(i = p_{i - 1}\) 的情况,需要将 \(i\) 向前面翻转,再往后翻到 \(p_i\) 处。

这种做法可能会被 hack 到 \(2n\),于是考虑在翻转的过程中随机抽取左端点,则 \(i = p_{i - 1}\) 出现的期望次数就很少了。

这种做法依然可能被小 \(n\) 叉飞。所以我们多次随机化,或者倒着做一遍,并且在随机化前面随机翻转 \(0\sim 100\) 个区间避免出现 \((2, 1, 3, 4, 5)\) 之类的情况,这种情况如果直接采取我们那种策略是无法通过的。

然后就过了。实际上不加最后的一步也能过,可见数据有多水。

实际上对于 \((2, 1, 3, 4, 5, \cdots)\) 的情况是存在一种操作方式的,可以依次翻转 \([2, n], [1, n], [2, n], [3, n]\) 解决,其余类似的情况也是同理。只不过前面的随机打乱策略已经可以通过,就没有加进代码里。

#include <bits/stdc++.h>
#define fi first
#define se second
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
#define lc(x) (tr[x].ls)
#define rc(x) (tr[x].rs)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
typedef __int128 i128;
using pi = pair<int, int>;
mt19937_64 rnd((unsigned)time(NULL));
const int N = 3005;
ll rd(ll l, ll r)
{
    return uniform_int_distribution<ll>(l, r)(rnd);
}
int n, a[N], pos[N], oria[N];
void flip(int l, int r)
{
    for(int i = l; i <= ((l + r) >> 1); i++)
        swap(a[i], a[r + l - i]);
    for(int i = l; i <= r; i++) pos[a[i]] = i;
}
vector<pi> ans;
void randshuf()
{
    int t = rd(0, 100);
    while(t--)
    {
        int l = rd(1, n - 2);
        int r = rd(l + 2, n);
        ans.push_back({l, r});
        flip(l, r);
    }
}
bool solve()
{
    for(int i = n; i >= 1; i--)
    {
        if(pos[i] == i) continue;
        if(pos[i] == i - 1)
        {
            if(1 > i - 3) return 0;
            int lx = rd(1, i - 3);
            ans.push_back({lx, i - 1});
            flip(lx, i - 1);
        }
        ans.push_back({pos[i], i});
        flip(pos[i], i);
    }
    if(ans.size() > 3000) return 0;
    cout << ans.size() << "\n";
    for(auto itm : ans) cout << itm.fi << " " << itm.se << "\n";  
    return 1;  
}
bool solve2()
{
    for(int i = 1; i <= n; i++)
    {
        if(pos[i] == i) continue;
        if(pos[i] == i + 1)
        {
            if(i + 3 > n) return 0;
            int rx = rd(i + 3, n);
            ans.push_back({i + 1, rx});
            flip(i + 1, rx);
        }
        ans.push_back({i, pos[i]});
        flip(i, pos[i]);
    }
    if(ans.size() > 3000) return 0;
    cout << ans.size() << "\n";
    for(auto itm : ans) cout << itm.fi << " " << itm.se << "\n";  
    return 1;  
}
int main()
{
    //freopen("sample.in", "r", stdin);
    //freopen("sample.out", "w", stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n;
    if(n <= 2)
    {
        cout << "-1";
        return 0;
    }
    for(int i = 1; i <= n; i++)
    {
        cin >> a[i];
        oria[i] = a[i];
        pos[a[i]] = i;
    }
    int t = 100;
    while(t--)
    {
        ans.clear();
        randshuf();
        if(solve()) return 0;
        memcpy(a, oria, sizeof(a));
        for(int i = 1; i <= n; i++)
            pos[a[i]] = i;
    }
    t = 100;
    while(t--)
    {
        ans.clear();
        randshuf();
        if(solve2()) return 0;
        memcpy(a, oria, sizeof(a));
        for(int i = 1; i <= n; i++)
            pos[a[i]] = i;
    }
    cout << -1;
    return 0;
}
posted @ 2026-01-18 05:03  KS_Fszha  阅读(6)  评论(0)    收藏  举报