zoukankan      html  css  js  c++  java
  • 「题解」Codeforces 1268C K Integers

    对于 (f(k)) 的计算,先计算把 (1sim k) 移成连续段,然后再计算逆序对数(最小交换次数使得一个排列排好序)。

    至于为什么是对的?感性理解一下,首先排好序一定要有个逆序对的代价,假如两个数之间没有相邻,则交换它们需要一步一步走过去,这样的花费就高了。

    考虑 (f(k-1) o f(k)) 新增的代价,计算逆序对数是容易的,(k) 只可能作为逆序对的第一个数,而第二个数可能的取值 ([1,k-1]) 都已经出现过,所以直接计算全局中以 (k) 为开头的逆序对数,树状数组易做到。

    计算把 (1sim k) 移成连续段的代价,有个经典结论就是移到中位数处,如果长度为偶数,移到中间两个的哪个都行。

    因为每个数不能移动到同一位置,所以代价计算会很麻烦,那就钦点让每个数可以移动到同一位置,最后再减去多余代价也就是两个等差数列即可。

    现在计算每个数移动到中位数处的距离,注意到每加入一个 (k) 之后中位数的最多会移动 (1) 个位置,且移动之后除了 (k) 以外的值对总代价的贡献不变,直接用 set 维护 (1sim k) 出现的位置然后移动就可以了。

    其实可以不用维护中位数,直接用树状数组记录哪些位置出现了数然后倍增找中位数也可以,常数更小。

    代码可能不大像说人话的样子,看看思路就好了。

    #include<iostream>
    #include<cstdio>
    #include<vector>
    #include<set>
    #define pb push_back
    #define mp std::make_pair
    #define fir first
    #define sec second
    typedef std::pair<int, int> pii;
    typedef std::vector<int> veci;
    typedef std::vector<pii> vecpii;
    typedef long long ll;
    ll Abs(ll x) { return x < 0 ? -x : x; }
    template <typename T>
    T& read(T& r) {
    	r = 0; bool w = 0; char ch = getchar();
    	while(ch < '0' || ch > '9') w = ch == '-' ? 1 : 0, ch = getchar();
    	while(ch >= '0' && ch <= '9') r = r * 10 + (ch ^ 48), ch = getchar();
    	return r = w ? -r : r;
    }
    inline int lowbit(int x) { return x & (-x); }
    const int N = 2000100;
    int n, a[N], pos[N];
    struct BIT {
    	int tree[N];
    	int sumq(int x) { int sum = 0; for(; x; x -= lowbit(x)) sum += tree[x]; return sum; }
    	void modify(int x, int v) { for(; x <= n; x += lowbit(x)) tree[x] += v; }
    }tr;
    ll ans[N], c[N];
    std::set<int>st;
    ll calc(ll x) { return x * (x + 1) / 2; } 
    signed main() {
    	read(n);
    	for(int i = 1; i <= n; ++i) read(a[i]), pos[a[i]] = i;
    	for(int i = n; i; --i) {
    		c[a[i]] = tr.sumq(a[i]);
    		tr.modify(a[i], 1);
    	}
    	int p = 1, num = 1; st.insert(pos[1]);
    	for(int i = 2; i <= n; ++i) {
    		ans[i] = ans[i-1] + c[i];
    		if(!(i&1)) {
    			ans[i] += Abs(pos[num] - pos[i]);
    			if(pos[i] < pos[num]) ++p;
    			st.insert(pos[i]);
    			continue ;
    		}
    		st.insert(pos[i]);
    		if(pos[i] < pos[num]) ++p;
    		if(p != (i+1)/2) {
    			auto it = st.lower_bound(pos[num]);
    			if(pos[i] < pos[num]) --it, --p;
    			else ++it, ++p;
    			num = a[*it];
    		}
    		ans[i] += Abs(pos[num] - pos[i]);
    	}
    	for(int i = 1; i <= n; ++i) printf("%lld ", ans[i] - calc((i-1)/2) - calc(i/2));
    	return 0;
    }
    
  • 相关阅读:
    hihocoder 1049 后序遍历
    hihocoder 1310 岛屿
    Leetcode 63. Unique Paths II
    Leetcode 62. Unique Paths
    Leetcode 70. Climbing Stairs
    poj 3544 Journey with Pigs
    Leetcode 338. Counting Bits
    Leetcode 136. Single Number
    Leetcode 342. Power of Four
    Leetcode 299. Bulls and Cows
  • 原文地址:https://www.cnblogs.com/do-while-true/p/15321783.html
Copyright © 2011-2022 走看看