[Acwing241]楼兰图腾
一、题目
二、思路
大致题意就是寻找左右两边比当前位置大的数和比当前位置小的数的个数,求满足题目里的条件的组合的个数。
用树状数组来存储每个数字加入后该数出现的次数,第一遍循环从左往右找比第i个数小的数存到low数组里,再找比第i个数大的数存到gre数组里,第二遍循环从右往左找比第i个数小的数量乘上之前的low数组加到resn里就是^符号可以组成的次数,找比第i个数大的数量乘上之前的gre数组加到resv里就是v符号可以组成的次数。
三、代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 200010;
ll t[N], a[N], low[N], gre[N];
int n;
int lowbit(int x){
return x & (-x);
}
void add(int x, int k){ //树状数组添加操作,因为这题只需要判断是否出现,加1即可
for(int i = x; i <= n; i += lowbit(i)){
t[i] += k;
}
}
int getsum(int x){ //求比x小的数出现的个数
int sum = 0;
for(int i = x; i >= 1; i -= lowbit(i)){
sum += t[i];
}
return sum;
}
int main(){
cin >> n;
for(int i = 1; i <= n; i ++){
cin >> a[i];
}
for(int i = 1; i <= n; i ++){
int y = a[i];
low[i] = getsum(y - 1);
gre[i] = getsum(n) - getsum(y);
add(y, 1);
}
memset(t, 0, sizeof t);
ll resv = 0, resn = 0;
for(int i = n; i > 0; i --){
int y = a[i];
resv += gre[i] * (getsum(n) - getsum(y));
resn += low[i] * getsum(y - 1);
add(y, 1);
}
cout << resv << " " << resn << endl;
return 0;
}
四、碎碎念
加油学树状数组,搞好线段树!



浙公网安备 33010602011771号