• ch4201 楼兰图腾


    题目链接:https://ac.nowcoder.com/acm/contest/1032/A

    简单题意:给定序列a,分别求出ai<aj>ak和ai>aj<ak(i,j,k互不相同)的对数

    考虑ai<aj>ak。用和求逆序对类似的方法,正反向两次枚举,分别求出对于每个aj(即枚举三个数中间的数)左边比它小的数和右边比它大的数各有多少个,分别为l[i]和r[i],则Σ(l[i]*r[i])就是答案。ai>aj<ak同理

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    
    const int N=2e5+10;
    int l[N],r[N],c[N],a[N],n,m,i,j,k;
    
    void add(int x,int y){
    	for (int i=x;i<=n;i+=(i&-i)) c[i]+=y;
    }
    int ask(int x){
    	int res=0;
    	for (int i=x;i>0;i-=(i&-i)) res+=c[i];
    	return res;
    }
    
    int main(){
    	scanf("%d",&n);
    	for (i=1;i<=n;i++) scanf("%d",&a[i]);
    	for (i=1;i<=n;i++) {
    	  l[i]=ask(n)-ask(a[i]); add(a[i],1);
    	}
    	memset(c,0,sizeof(c));
    	for (i=n;i>=1;i--){
    	  r[i]=ask(n)-ask(a[i]); add(a[i],1);
    	}
    	ll ans1=0;
    	for (i=1;i<=n;i++) ans1+=(l[i]*r[i]);
    	memset(c,0,sizeof(c));
    	for (i=1;i<=n;i++){
    	  l[i]=ask(a[i]-1); add(a[i],1);
    	}
    	memset(c,0,sizeof(c));
    	for (i=n;i>=1;i--){
    	  r[i]=ask(a[i]-1); add(a[i],1);
    	}
    	ll ans2=0;
    	for (i=1;i<=n;i++) ans2+=(l[i]*r[i]);
    	printf("%lld %lld",ans1,ans2);
    	return 0; 
    }
    

      

  • 相关阅读:
    <form:select>的使用
    存储过程-删除、新建索引
    java 反射常用总结
    java判断是否是数字
    jquery遍历数组添加行删除行
    oracle常用sql
    cxf (zhuan)
    linux 常用命令--个人小结一
    java发送邮件
    socket和webservice特点
  • 原文地址:https://www.cnblogs.com/edmunds/p/13620384.html
Copyright © 2020-2023  润新知