• TYVJ1432 楼兰图腾


    Description

    平面上有 N(N≤〖10〗^5 ) 个点,每个点的横、纵坐标的范围都是 1~N,任意两个点的横、纵坐标都不相同。
    若三个点 (x_1,y_1),(x_2,y_2),(x_3,y_3 ) 满足 x_1<x_2<x_3, y_1>y_2 并且 y_3>y_2,则称这三个点构成"v"字图腾。
    若三个点 (x_1,y_1),(x_2,y_2),(x_3,y_3 ) 满足 x_1<x_2<x_3, y_1<y_2 并且 y_3<y_2,则称这三个点构成"^"字图腾。
    求平面上"v"和"^"字图腾的个数。

    Input

    第一行一个数n 
    第二行是n个数,分别代表y1,y2……yn

    Output

    两个数中间用空格隔开 依次为V的个数和∧的个数

    Sample Input

    5
    1 5 3 2 4

    Sample Output

    3 4

    这题乍一看水题,暴力O(n^2)好像可以过

    仔细算就会发现,不行!!!

    那我们就需要一种O(nlogn),甚至O(n)的算法

    看“v”和“^”的满足条件有一些是不是很像线段树求逆序对呢

    逆序对求法(线段树):逆序对

    (其实我也不知道为什么,队测时自然想到线段树,没敢敲(吐血),错估了时间复杂度,以为是不如暴力的O(n^2logn))

    还有一点,至少乘法原理你得想到吧,不知道的自己去学

    先给暴力做法:

     1 #include<cstdio>
     2 int n,m,d[100001];long long ans1,ans2;
     3 int main()
     4 {
     5     scanf("%d",&n);
     6     for(int i=1;i<=n;i++)scanf("%d",&d[i]);
     7     for(int i=1;i<=n;i++)
     8     {
     9         int lx=0,rx=0,ll=0,rr=0;
    10         for(int j=1;j<i;j++)
    11             if(d[j]<d[i])lx++;
    12             else ll++;
    13         for(int j=i+1;j<=n;j++)
    14             if(d[j]<d[i])rx++;
    15             else rr++;
    16         ans1+=ll*rr;
    17         ans2+=lx*rx;    
    18     }
    19     printf("%lld %lld",ans1,ans2);
    20 } 

    这个是最朴实无华的暴力了(TLE大法)

    请看这句话(每个点的横、纵坐标的范围都是 1~N)

    依据这个,可以小小优化暴力,下面给出暴力优化(并没有什么用,依然是TLE大法):

     1 #include<cstdio>
     2 int n,m,d[100001];long long ans1,ans2;
     3 int main()
     4 {
     5     scanf("%d",&n);
     6     for(int i=1;i<=n;i++)scanf("%d",&d[i]);
     7     for(int i=1;i<=n;i++)
     8     {
     9         int lx=0,ll=0;
    10         for(int j=1;j<i;j++)
    11             if(d[j]<d[i])ll++;
    12             else lx++;
    13         ans1+=ll*(d[i]-1-ll);
    14         ans2+=lx*(n-d[i]-lx);    
    15     }
    16     printf("%lld %lld",ans2,ans1);
    17 } 

    以上纯属娱乐,相信大家都会写

    那个优化可有用,那么让我们来看正解吧

    线段树(或树状数组)

     1 #include<cstdio>
     2 #include<algorithm>
     3 using namespace std;
     4 int n,ans1,ans2;long long ans0,ans;
     5 struct oo{int a,b,v;}s[800001];
     6 void build(int x,int l,int r)
     7 {
     8     s[x].a=l,s[x].b=r;
     9     if(l==r)return ;
    10     build(x<<1,l,l+r>>1);
    11     build(x<<1|1,(l+r>>1)+1,r);
    12 }
    13 void change(int x,int y)
    14 {
    15     s[x].v++;
    16     if(s[x].a==s[x].b)return ;
    17     int mid=s[x].a+s[x].b>>1;
    18     if(y<=mid)change(x<<1,y);
    19     else change(x<<1|1,y);
    20 }
    21 void get(int x,int y)
    22 {
    23     if(y>s[x].b){ans1+=s[x].v;return ;}
    24     if(y<s[x].a){ans2+=s[x].v;return ;}
    25     if(s[x].a==s[x].b)return ;
    26     get(x<<1,y);get(x<<1|1,y);
    27 }
    28 int main()
    29 {
    30     scanf("%d",&n);
    31     build(1,1,200000);
    32     for(int i=1,x;i<=n;i++)
    33     {
    34         ans1=ans2=0;
    35         scanf("%d",&x),change(1,x);
    36         get(1,x);
    37         ans0+=ans1*(x-1-ans1),ans+=ans2*(n-x-ans2);
    38     }
    39     printf("%lld %lld",ans,ans0);
    40 }

    很短吧!!

    祝大家早日AC!!!

  • 相关阅读:
    JAVA课上课后问题总结(2019.09.20)
    JAVA课后问题汇总(第三次课)
    java课后作业:记录创建对象数
    《程序员修炼之道》读后感(一)【第二章与第三章】
    [java web]小学四则运算出题系统
    apache连接数
    isql导出表到文本
    iis6上的FTP有缓存
    Perl 标量的操作符
    apachetomcat
  • 原文地址:https://www.cnblogs.com/lcxer/p/9441515.html
Copyright © 2020-2023  润新知