zoukankan      html  css  js  c++  java
  • hdu1394(枚举/树状数组/线段树单点更新&区间求和)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394

    题意:给出一个循环数组,求其逆序对最少为多少;

    思路:对于逆序对: 交换两个相邻数,逆序数 +1 或 -1, 交换两个不相邻数 a, b, 逆序数 += 两者间大于 a 的个数 - 两者间小于 a 的个数;

    所以只要求出初始时的逆序对数,就可以推出其余情况时的逆序对数.对于求初始逆序对数,这里 n 只有 5e3,可以直接暴力 / 树状数组 / 线段树 / 归并排序;

    代码:

    1.直接暴力

     1 #include <iostream>
     2 #include <stdio.h>
     3 using namespace std;
     4 
     5 const int MAXN = 5e3 + 10;
     6 int a[MAXN];
     7 
     8 int  main(void){
     9     int n, ans = 0;
    10     while(~scanf("%d", &n)){
    11         ans = 0;
    12         for(int i = 0; i < n; i++){
    13             scanf("%d", &a[i]);
    14             for(int j = 0; j < i; j++){
    15                 if(a[j] > a[i]) ans++;
    16             }
    17         }
    18         int cnt = ans;
    19         for(int i = 0; i < n; i++){
    20             cnt += (n - a[i] - 1) - a[i];
    21             ans = min(ans, cnt);
    22         }
    23         printf("%d
    ", ans);
    24     }
    25     return 0;
    26 }
    View Code

    2.树状数组

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <string.h>
     4 using namespace std;
     5 
     6 const int MAXN = 5e3 + 10;
     7 int tree[MAXN], a[MAXN], n;
     8 
     9 int lowbit(int x){
    10     return x & (-x);
    11 }
    12 
    13 void updata(int x, int d){
    14     while(x <= n){
    15         tree[x] += d;
    16         x += lowbit(x);
    17     }
    18 }
    19 
    20 int sum(int x){
    21     int ans = 0;
    22     while(x > 0){
    23         ans += tree[x];
    24         x -= lowbit(x);
    25     }
    26     return ans;
    27 }
    28 
    29 int main(void){
    30     int ans = 0;
    31     while(~scanf("%d", &n)){
    32         ans = 0;
    33         memset(tree, 0, sizeof(tree));
    34         for(int i = 1; i <= n; i++){
    35             scanf("%d", &a[i]);
    36             updata(a[i] + 1, 1);
    37             ans += i - sum(a[i] + 1);//当前是第 i 个数,减去a[i]前面(这里包括了a[i])的数就是a[i]后面的数了,即可以和a[i]组成逆序对的数的数目
    38             // ans += sum(n) - sum(a[i] + 1);
    39         }
    40         int cnt = ans;
    41         for(int i = 1; i <= n; i++){
    42             cnt += (n - a[i] - 1) - a[i];
    43             ans = min(ans, cnt);
    44         }
    45         printf("%d
    ", ans);
    46     }
    47     return 0;
    48 }
    View Code

    3.线段树

     1 #include <iostream>
     2 #include <stdio.h>
     3 #define lson l, mid, rt << 1
     4 #define rson mid + 1, r, rt << 1 | 1
     5 using namespace std;
     6 
     7 const int MAXN = 5e3 + 10;
     8 int sum[MAXN << 2], a[MAXN];
     9 
    10 void push_up(int rt){
    11     sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
    12 }
    13 
    14 void build(int l, int r, int rt){
    15     sum[rt] = 0;
    16     if(l == r) return;
    17     int mid = (l + r) >> 1;
    18     build(lson);
    19     build(rson);
    20 }
    21 
    22 void update(int p, int x, int l, int r, int rt){
    23     if(l == r){
    24         sum[rt] += x;
    25         return;
    26     }
    27     int mid = (l + r) >> 1;
    28     if(p <= mid) update(p, x, lson);
    29     else update(p, x, rson);
    30     push_up(rt);
    31 }
    32 
    33 int query(int L, int R, int l, int r, int rt){
    34     if(l >= L && r <= R) return sum[rt];
    35     int mid = (l + r) >> 1;
    36     int ans = 0;
    37     if(L <= mid) ans += query(L, R, lson);
    38     if(R > mid) ans += query(L, R, rson);
    39     return ans;
    40 }
    41 
    42 int main(void){
    43     int n, ans = 0;
    44     while(~scanf("%d", &n)){
    45         ans = 0;
    46         build(0, n-1, 1);
    47         for(int i = 0; i < n; i++){
    48             scanf("%d", &a[i]);
    49             ans += query(a[i], n - 1, 0, n - 1, 1);
    50             update(a[i], 1, 0, n - 1, 1);
    51         }
    52         int cnt = ans;
    53         for(int i = 0; i < n; i++){
    54             cnt += (n - a[i] - 1) - a[i];
    55             ans = min(ans, cnt);
    56         }
    57         printf("%d
    ", ans);
    58     }
    59     return 0;
    60 }
    View Code
  • 相关阅读:
    Cisco静态路由
    VTP
    trunk
    vim中文乱码
    Ubuntu 切换root用户是时出现su Authentication failure
    github 换行符自动转换功能
    Qt弹出消息对话框
    串口发送Hex数组
    Qt 按顺序保存多个文件
    Qt乱码解决办法(常量中有换行符)
  • 原文地址:https://www.cnblogs.com/geloutingyu/p/6984492.html
Copyright © 2011-2022 走看看