1 条题解

  • 0
    @ 2026-5-1 23:05:48

    题目大意

    给定一个长度为 NN 的序列 did_i

    你有一个长度为 NN 的序列 aia_i,初始状态下 ai=ia_i=i

    你需要每次交换序列 aia_i 中相邻的两个数,使得最终满足对于任意的 1in1\le i\le n,均有 aidia_i\le d_i。求出最少需要多少次。

    分析

    假设我们已经构造出了序列 aa,那么最小的交换次数就是序列 aa 中逆序对的数量。

    所以,问题就转化成了:构造一个 11nn 的排列 aa,使得 aidia_i\le d_i,且 aa 中逆序对的数量尽可能少。

    可以发现,我们需要让排在后面的数尽可能的大,才能使得逆序对的数量尽可能少。

    这里用了一个树状数组维护当前已经填充过的数,并用一个二分来对当前最大的满足限制的数进行查找。

    #include<bits/stdc++.h>
    typedef long long ll;
    using namespace std;
    int n;
    int a[200005], pre[200005];
    int c[200005];
    ll tot;
    void add(int x) {
    	for(; x <= n ;  x += x & -x) c[x]++; 
    }
    int ask(int x) {
    	if(x == 0) return 0;
    	int ans = 0;
    	for(; x ; x -= x & -x) ans += c[x];
    	return ans; 
    }
    int main() {
    	scanf("%d", &n);
    	for(int i = 1; i <= n; i++) {
    		scanf("%d", &a[i]);
    	}
    	for(int i = n; i >= 1; i--) {
    		int l = 1, r = a[i], mid, ans = -1, sum = ask(a[i]);
    		while(l <= r) {
    			mid = l + r >> 1;
    			if(sum - ask(mid - 1) < a[i] - mid + 1) l = mid + 1, ans = mid;
    			else r = mid - 1;
    		}
    		if(ans == -1) {
    			puts("-1");
    			return 0;
    		}
    		tot += ask(ans);
    		add(ans);
    	}
    	printf("%lld", tot);
    	return 0;
    }
    
    • 1

    信息

    ID
    10630
    时间
    1000ms
    内存
    512MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者