zoukankan      html  css  js  c++  java
  • codeforces 1269E K Integers (二分+树状数组)

    链接:https://codeforces.com/contest/1269/problem/E

    题意:给一个序列P1,P2,P3,P4....Pi,每次可以交换两个相邻的元素,执行最小次数的交换移动,使得最后存在一个子段1,2,…,k,这是题目所定义的f(k),题目要求求出所有的f(n),并依次输出。

    思路:首先考虑逆序对问题,比如3 2 1 4这个序列,要使其变为1 2 3 4,最小的移动次数是这个序列中逆序对之和,2+1 = 3,逆序对是(3,2) (3,1)(2,1),但是在比如序列3 5 2 1 6 7 4 8 9,求f(4)怎么做?首先是不是把1 2 3 4这个序列聚成在一起,相连在一起,再去计算逆序对个数,两个过程所花费相加就是答案。那么这个题目就分为两个过程,1.聚合n个数字在一起。2.求逆序对的个数,两者花费相加就行。第1个过程如果使得聚合步数最少呢?其实就是求出聚合后的最中间的位置,其他所有的数字向这个位置靠近所花费的移动次数是最少的,这个过程可以用二分做。第2个过程可以用树状数组,也可以用线段树做。输入的时候记录每个数字的位置,建两个树状数组,一个树状数组维护数字出现的次数,用来求逆序对个数,另一个树状数组维护各个数字在原序列的位置。

    AC代码:

     1 #include<iostream>
     2 #include<string>
     3 #include<vector>
     4 #include<cstring>
     5 #include<cstdio>
     6 #include<algorithm>
     7 #include<cmath>
     8 using namespace std;
     9 typedef long long ll;
    10 ll mod = 1e9+7;
    11 const int maxn = 2e5+10;
    12 ll t[maxn],cnt[maxn]; 
    13 ll pos[maxn];
    14 int n;
    15 inline int lowbit(ll x){
    16     return x&(-x);
    17     ///算出x二进制的从右往左出现第一个1以及这个1之后的那些0组成数的二进制对应的十进制的数
    18 }
    19 void add(ll *b , int x, int k) {//单点修改 
    20   while (x <= n) {  //不能越界
    21     b[x] = b[x] + k;
    22     x = x + lowbit(x);
    23   }
    24 }
    25 ll getsum(ll *b,int x) {  // a[1]……a[x]的和
    26   ll ans = 0;
    27   while (x > 0) {
    28     ans = ans + b[x];
    29     x = x - lowbit(x);
    30   }
    31   return ans;
    32 }
    33 int main(){
    34     ios::sync_with_stdio(false);
    35     cin.tie(0);
    36     cin>>n;
    37     for(int i = 1;i<=n;i++){
    38         int t;
    39         cin>>t;
    40         pos[t] = i;
    41     }
    42     ll inv = 0;
    43     for(int i = 1;i<=n;i++){
    44         inv += (i-1-getsum(t,pos[i]));
    45         add(t,pos[i],1);
    46         add(cnt,pos[i],pos[i]);
    47         if(i==1){
    48             cout<<0<<" ";
    49             continue;
    50         }
    51         int mid,l = 1,r = n;
    52         while(l<=r){
    53             mid = (l+r)>>1;
    54             if(getsum(t,mid)*2<=i){
    55                 l = mid+1;
    56             }
    57             else{
    58                 r = mid-1;
    59             }
    60         }    
    61         ll ans = 0;
    62         ll cntL = getsum(t,mid);
    63         ll cntR = i - cntL;
    64         ll indexL = getsum(cnt,mid);
    65         ll indexR = getsum(cnt,n)-indexL;
    66         ans+=((mid+mid-cntL+1)*cntL)/2-indexL;
    67         ans+=(indexR-((mid+1+(mid+cntR))*cntR)/2);
    68         cout<<ans+inv<<" ";
    69     }
    70     return 0;
    71 }
  • 相关阅读:
    Java实现 LeetCode 27 移除元素
    Java实现 LeetCode 26 删除排序数组中的重复项
    Java实现 LeetCode 26 删除排序数组中的重复项
    Java实现 LeetCode 26 删除排序数组中的重复项
    Java实现 LeetCode 25 K个一组翻转链表
    Java实现 LeetCode 25 K个一组翻转链表
    Java实现 LeetCode 25 K个一组翻转链表
    Java实现 LeetCode 24 两两交换链表中的节点
    Java实现 LeetCode 24 两两交换链表中的节点
    Java实现 LeetCode 24 两两交换链表中的节点
  • 原文地址:https://www.cnblogs.com/AaronChang/p/12147535.html
Copyright © 2011-2022 走看看