zoukankan      html  css  js  c++  java
  • CSAcademy Beta Round #4 Swap Pairing

    题目链接:https://csacademy.com/contest/arhiva/#task/swap_pairing/

    大意是给2*n个包含n种数字,每种数字出现恰好2次的数列,每一步操作可以交换相邻的两个数字,问最少需要操作多少次,可以使得所有的同种数字都相邻。

    我的做法是考虑不同的数对的数字在原来数列中的位置关系,有三大类,如果我们用[]和{}表示的话就是:

    []{}

    [{]}

    [{}]

    这三种位置情况。

    第一种情况对答案的贡献应当是0。

    第二种情况对答案的贡献应当是1。

    第三种情况对答案的贡献应当是2。

    接下来问题就是如何统计。我的方法是先计算所有的pair对,

    总共n种数字,那么数对的个数就是(n-1)*n/2。

    接下来需要减去第一种情况的个数,再加上第三种情况的个数。

    第一种情况的统计应当是比较简单的,第三种情况可以规约到求某个线段内部有多少线段的问题。

    统计可以用BIT来维护。

    代码如下:

     1 #include <iostream>
     2 #include <vector>
     3 #include <algorithm>
     4 #include <string>
     5 #include <string.h>
     6 #include <stdio.h>
     7 #include <math.h>
     8 #include <queue>
     9 #include <stack>
    10 #include <map>
    11 #include <ctime>
    12 #include <set>
    13 using namespace std;
    14 
    15 const int N=123456;
    16 int a[N];
    17 map<int,int> le;
    18 map<int,int> ri;
    19 
    20 pair<int,int> pos[N];
    21 int v[N];
    22 int lowbit(int x) {
    23     return x & -x;
    24 }
    25 int get(int x) {
    26     int ret=0;
    27     while (x) {
    28         ret+=v[x];
    29         x-=lowbit(x);
    30     }
    31     return ret;
    32 }
    33 void add(int x,int add) {
    34     while (x<N) {
    35         v[x]+=add;
    36         x+=lowbit(x);
    37     }
    38 }
    39 int main () {
    40     int n;
    41     while (scanf("%d",&n)!=EOF) {
    42         memset(v,0, sizeof(v));
    43         le.clear();
    44         ri.clear();
    45         for (int i=1;i<=n;i++) {
    46             scanf("%d",a+i);
    47             if (le[a[i]]==0)
    48                 le[a[i]]=i;
    49             else ri[a[i]]=i;
    50         }
    51         int cnt=1;
    52         for (map<int,int>::iterator it=le.begin();it!=le.end();it++) {
    53             int key=it->first;
    54             int val1=it->second;
    55             int val2=ri[key];
    56             pos[cnt].first=val1;
    57             pos[cnt++].second=val2;
    58         }
    59         sort(pos+1,pos+cnt);
    60         int tot=n/2;
    61         long long ret=(tot-1)*1LL*tot/2LL;
    62         for (int i=tot;i>=1;i--) {
    63             int l=pos[i].first;
    64             int r=pos[i].second;
    65             ret+=get(r);
    66             add(r,1);
    67         }
    68         memset(v,0,sizeof v);
    69         for (int i=1;i<=tot;i++) {
    70             int l=pos[i].first;
    71             int r=pos[i].second;
    72             ret-=get(l);
    73             add(r,1);
    74         }
    75         cout<<ret<<endl;
    76 
    77     }
    78 }
    View Code

    题解给了另一种做法,可以有一种最优解第一个数字不用移动,则接下来所有数字怎么移动都被固定了,中间仍然是用BIT来维护。

  • 相关阅读:
    C# 进程间通信之二传递复杂数据类型(转)
    c# 进程间的通信实现之一简单字符串收发
    WinRAR压缩操作帮助类
    软件推荐:扫码格式检测系统
    C#位操作(转)
    浅析c#内存泄漏
    常用SQL语句
    linux下网站搭建
    VS中的活动debug和活动cpu
    让程序员跳槽的非钱原因
  • 原文地址:https://www.cnblogs.com/micrari/p/5438521.html
Copyright © 2011-2022 走看看