zoukankan      html  css  js  c++  java
  • P1774 最接近神的人_NOI导刊2010提高(02)

    题目描述

    破解了符文之语,小FF开启了通往地下的道路。当他走到最底层时,发现正前方有一扇巨石门,门上雕刻着一幅古代人进行某种活动的图案。而石门上方用古代文写着“神的殿堂”。小FF猜想里面应该就有王室的遗产了。但现在的问题是如何打开这扇门……

    仔细研究后,他发现门上的图案大概是说:古代人认为只有智者才是最容易接近神明的。而最聪明的人往往通过一种仪式选拔出来。仪式大概是指,即将隐退的智者为他的候选人写下一串无序的数字,并让他们进行一种操作,即交换序列中相邻的两个元素。而用最少的交换次数使原序列变成不下降序列的人即是下一任智者。

    小FF发现门上同样有着n个数字。于是他认为打开这扇门的秘诀就是找到让这个序列变成不下降序列所需要的最小次数。但小FF不会……只好又找到了你,并答应事成之后与你三七分……

    输入输出格式

    输入格式:

    第一行为一个整数n,表示序列长度

    第二行为n个整数,表示序列中每个元素。

    输出格式:

    一个整数ans,即最少操作次数。

    输入输出样例

    输入样例#1:
    4
    2 8 0 3
    
    输出样例#1:
    3
       样例说明:开始序列为2 8 0 3,目标序列为0 2 3 8,可进行三次操作的目标序列:
        1.Swap (8,0):2  0  8  3
        2.Swap (2,0):0  2  8  3
        3.Swap (8,3):0  2  3  8
    

    说明

    对于30%的数据1≤n≤10^4。

    对于100%的数据1≤n≤5*10^5;

    -maxlongint≤A[i]≤maxlongint。

    这题用归并排序可以水过。

    但是我用了树状数组+离散化+二分

    首先,树状数组中存的是小于等于当前位置的数的个数

    我们先把原来的数组排序,然后每次利用二分的方式求出待求的数在排好序的序列中出现的位置

    这是因为是按顺序枚举,所以我们每次默认有i个数比正在枚举的数大,那么我们用树状数组找出小于当前数的个数即可

    最后一减就是答案

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cmath>
     5 #include<algorithm>
     6 #define lli long long int 
     7 using namespace std;
     8 const lli MAXN=2000001;
     9 lli lowbit(lli p)
    10 {
    11     return p&-p;
    12 }
    13 void read(lli &n)
    14 {
    15     char c='+';lli x=0;bool flag=0;
    16     while(c<'0'||c>'9')
    17     {c=getchar();if(c=='-')flag=1;}
    18     while(c>='0'&&c<='9')
    19     {x=x*10+(c-48);c=getchar();}
    20     flag==1?n=-x:n=x;
    21 }
    22 lli a[MAXN];
    23 lli tree[MAXN],mp[MAXN];
    24 lli n;
    25 lli query(lli p)
    26 {
    27     lli tot=0;
    28     while(p)
    29     {
    30         tot+=tree[p];
    31         p=p-lowbit(p);
    32     }
    33     return tot;
    34 }
    35 void add(lli p)
    36 {
    37     while(p<=MAXN/2)
    38     {
    39         tree[p]++;
    40         p+=lowbit(p);
    41     }
    42 }
    43 int erfen(int num)
    44 {
    45     int l=1,r=n;
    46     while(l<r)
    47     {
    48         int mid=(l+r)>>1;
    49         if(mp[mid]==num)
    50             return mid;
    51         if(mp[mid]>num)
    52             r=mid-1;
    53         if(mp[mid]<num)
    54             l=mid+1;
    55     }
    56     return l;
    57 }
    58 int main()
    59 {
    60 //    memset(tree,0,sizeof(tree));
    61     read(n);
    62     lli ans=0;
    63     for(lli i=1;i<=n;i++)
    64     {
    65         read(a[i]);
    66         mp[i]=a[i];
    67     }
    68     sort(mp+1,mp+n+1);
    69     for(int i=1;i<=n;i++)
    70     {
    71         int p=erfen(a[i]);
    72         add(p);
    73         ans+=i-query(p);
    74     }
    75     printf("%lld",ans);
    76     return 0;
    77 }
  • 相关阅读:
    修改tableVIewCell里控件的属性
    常用正则表达式
    解决定时器在主线程不工作问题
    iOS App集成Apple Pay
    使用UIDataDetectorTypes自动检测电话、网址和邮箱
    NSDictionary初始化的坑
    关于UIViewController的presentViewController实现
    iOS8以上使用CoreLocation定位
    .xib 创建的文件 [self.view bringSubviewToFront:XXX];不好用
    socket通讯----GCDAsyncSocke 解读
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/7099572.html
Copyright © 2011-2022 走看看