题目描述
题解:
题目又臭又长,我来简化一下
其实就是问有多少个山峰,有多少个山谷
山峰就是^
山谷就是v
线段树和树状数组都可以做
用到两个变量right_num和left_num
right_num[i]表示在i的右边比i小的数有多少
left_num[i]表示在i的左边比i小的数有多少
求出两个数组之后,我们要求山峰不就是要知道左右两边比他小的数量吗。所以直接left_num[i]right_num[i]
求山谷就正好反过来,(i-1-left_num[i])(n-i-right_num[i])即可
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 200006;
typedef long long ll;
ll n,a[maxn],c[maxn],left_num[maxn],right_num[maxn];
int lowbit(int x)
{
return x=x&(-x);
}
void insert(int x,int y)
{
while(y<=n)
{
c[y]+=x;
y+=lowbit(y);
}
}
int getsum(int x)
{
int sum = 0;
while(x>0)
{
sum+=c[x];
x-=lowbit(x);
}
return sum;
}
int main(int argc, char const *argv[])
{
scanf("%d",&n);
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=n;i;i--)
{
int k = getsum(a[i]);
insert(1,a[i]);
right_num[i]=k;
}
for(int i=1;i<=n;i++)c[i]=0;
for(int i=1;i<=n;i++)
{
int k = getsum(a[i]);
insert(1,a[i]);
left_num[i]=k;
}
long long ans1 = 0;
for(int i=1;i<=n;i++)
{
ans1+=left_num[i]*right_num[i];
}
long long ans2 = 0;
for(int i=1;i<=n;i++)
{
ans2+=(i-1-left_num[i])*(n-i-right_num[i]);
}
cout<<ans2<<" "<<ans1<<endl;
return 0;
}线段树代码;
#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
#include <cmath>
#include <map>
#include <climits>
using namespace std;
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
typedef long long ll;
const int INF=0x3f3f3f3f;
const int maxn=2e5+10;
int T,n,m,k;
int a[maxn];
int sum[maxn<<2];
void PushUp(int rt){
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void Update(int rt,int l,int r,int pos){
if(l==r){
sum[rt]++;
return ;
}
int mid=(l+r)>>1;
if(pos<=mid) Update(lson,pos);
else Update(rson,pos);
PushUp(rt);
}
ll Query(int rt,int l,int r,int L,int R){
if(L<=l&&r<=R) return sum[rt];
int mid=(l+r)>>1;
ll ans=0;
if(L<=mid) ans+=Query(lson,L,R);
if(R>mid) ans+=Query(rson,L,R);
return ans;
}
int main(){
scanf("%d",&n);
{
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
ll ans1=0,ans2=0;
for(int i=1;i<=n;i++){
ll tmp1=Query(1,1,n,1,a[i]);
ll tmp2=Query(1,1,n,a[i],n);
ans1+=tmp2*(n-a[i]-tmp2);
ans2+=tmp1*(a[i]-1-tmp1);
Update(1,1,n,a[i]);
}
printf("%lld %lld\n",ans1,ans2);
}
return 0;
}
京公网安备 11010502036488号