• 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 }
  • 相关阅读:
    OPENWRT 支持git
    LUCI MVC框架
    luci范例
    Hive | Hive可以避免进行MapReduce
    ORACLE日常-oracle中给date型字段insert into值
    ORACLE日常-ORACLE 中的 ROW_NUMBER() OVER() 分析函数的用法
    ORACLE日常-oracle字符串操作:拼接、替换、截取、查找
    HDFS中的shell操作
    java日常-map转成json
    java学习-reflection反射机制
  • 原文地址:https://www.cnblogs.com/AaronChang/p/12147535.html
Copyright © 2020-2023  润新知