CF1746C(构造)

CF1746C(构造)

https://codeforces.com/contest/1746/problem/c

题意

给一个排列,进行 \(n\) 次操作,第 \(i\) 次操作可以将任意指定长度的后缀加 \(i\)。问经过 \(n\) 次操作后,能使逆序最小的操作方案。

思路

首先可以发现,后面的数一定比前面的数有更多的增量,所以若干次操作不会让后缀产生新的逆序,每次操作只会让逆序数不增。于是,我们只需要考虑操作一次后和前缀的关系。

然后如果我们每次只考虑增量区间的端点,\(n\) 次操作可以构造出 \(n\)\(n+1\) 。当然这是在不考虑区间加,仅考虑每次操作对端点的影响,但是又由于上面说的,每次操作不会对后缀产生新的逆序,于是忽略除端点外的区间是可行的。

于是,构造单点更新情况下的 \(n\)\(n+1\)就可以得到答案。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
#include<bitset>
#include<queue>
#include<map>
#include<stack>
#include<string>
#include<random>
#include<cassert>
#include<functional>
#include<iomanip>
#define inf 0x3f3f3f3f
#define linf 0x3f3f3f3f3f3f3f3fll
#define endl '\n'
#define ll long long
#define int long long
#define SZ(x) (int)x.size()
#define rep(i,a,n) for(int i = (a);i <= (n);i++)
#define dec(i,n,a) for(int i = (n);i >= (a);i--)
using namespace std;
using PII = array<int,2>;
mt19937 mrand(random_device{}());
int rnd(int x) { return mrand() % x;}
const int N =10 + 2e5 ,mod=1e9 + 7;

void solve() {
	int n; cin >> n;
    vector<int> a(n + 1); rep(i, 1, n) cin >> a[i];

    vector<int> ans(n + 1);
    rep(i, 1, n) {
        ans[n - a[i] + 1] = i;
    }

    rep(i, 1, n) cout << ans[i] << " \n"[i == n];
}

signed main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

    int T;cin>>T;
    while(T--)
        solve();

    return 0;
}
posted @ 2022-10-16 19:30  Mxrurush  阅读(32)  评论(0编辑  收藏  举报