Codeforces Global Round 23 C. Permutation Operations

本文介绍了一种通过调整序列使其逆序对数量最小化的算法。该算法利用差分数组的概念,通过对序列进行特定操作,确保最终序列保持非递减状态,从而达到减少逆序对的目的。

赛时随便写了个做法,看standing,发现很多人的做法也是很奇特
赛后看了官方题解。。翻译下

题意:

每次可以给一个任意的后缀里的所有数 +i+i+i
执行n次。
使得逆序对最少。

思路:

tip1:

什么时候逆序对最少?
序列非递减。

解法:

处理出差分数组
d=[a2−a1,a3−a2,...,an−an−1]d = [a_2-a_1,a_3-a_2,...,a_n-a_{n-1}]d=[a2a1,a3a2,...,anan1]

那么什么时候序列非递减?转换为差分数组都是非负。

di=ai+1−ai,i∈[1,n−1]d_i = a_{i+1}-a_{i} ,i\in[1,n-1]di=ai+1ai,i[1,n1]
显然 di≥−aid_i \ge -a_idiai
那么我们可以对位置 i+1i+1i+1开始的后缀 +ai+a_i+ai.
由于每个aia_iai都是唯一的,所以可以构造出非递减序列。

最后输出的时候,注意 i=ni=ni=n时,就另ans[a[i]]=nans[a[i]] = nans[a[i]]=n即可。

AC(Java)

package com.hgs.codeforces.contest.globalround.contest23.c2;

/**
 * @author youtsuha
 * @version 1.0
 * Create by 2022/10/16 14:13
 */
import java.util.*;
import java.io.*;
public class Main {
    static FastScanner cin;
    static PrintWriter cout;

    private static void init()throws IOException {
        cin = new FastScanner(System.in);
        cout = new PrintWriter(System.out);
    }

    private static void close(){
        cout.close();
    }
    private static void sol()throws IOException {
        int n = cin.nextInt();
        int a[] = new int[n];
        for(int i = 0; i < n; i ++ ) {
            int p = cin.nextInt();
            p--;
            a[p] = (i + 1) + 1;
        }
        for(int i = 0; i < n; i ++ ) cout.print(Math.min(a[i],n) + " ");
        cout.println();
    }
    public static void main(String[] args) throws IOException {
        init();
        int tt = cin.nextInt();
        while(tt -- > 0)sol();
        close();
    }
}
class FastScanner {
    BufferedReader br;
    StringTokenizer st = new StringTokenizer("");

    public FastScanner(InputStream s) {
        br = new BufferedReader(new InputStreamReader(s));
    }

    public FastScanner(String s) throws FileNotFoundException {
        br = new BufferedReader(new FileReader(new File(s)));
    }

    public String next() throws IOException {
        while (!st.hasMoreTokens()){
            try {
                st = new StringTokenizer(br.readLine());
            } catch (IOException e) { e.printStackTrace(); }
        }
        return st.nextToken();
    }

    public int nextInt() throws IOException {
        return Integer.parseInt(next());
    }

    public long nextLong() throws IOException {
        return Long.parseLong(next());
    }

    public double nextDouble() throws IOException {
        return Double.parseDouble(next());
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值