Problem B: 平方2——分析,树状数组
Description
tw 很喜欢收集int范围内的数字,当有一天他终于收集到了N个数字,并把它们排成一排时,突然出现了一条神龙,神龙说我可以实现你一些愿望,你从这N个数字中找到符合x^2 < z^2 < y^2的偏序三元组(x,y,z)(即顺序为x在前,y在中间,z在后),这样的三元组的个数就是你能实现的愿望数
tw想知道他能实现多少愿望
Input
第一行:T代表T组数据
每组数据第一行:N
每组数据第二行:N个绝对值为10^9以内的数字
限制:
1 <= T <= 20
1 <= N <= 10^5
Output
对每组数据输出一行’Case #x: y’,代表第 x 组数据答案为 y
由于数字可能很大,请把答案对100000007取模
Sample Input
2
6
1 -3 -2 6 -5 4
5
3 5 2 4 1
Sample Output
Case #1: 10
Case #2: 1
分析:
把所有负数转换成正数,找到 x<z<y 的偏序三元组 (x,y,z) 即可。枚举 x ,后面比他大的数有 s 个,s选两个 (y,z) 有 s∗(s−1) 种。此时 y,z 无序。
因为题目要求 x<z<y ,那么我们只要再减去 x<y<z 的数量即可。
即如下公式
∑[x<z<y]=∑[x<y,z]−∑[x<y<z]
对于等号右边第一项,枚举 x < ( y , z ) 。
对于等号右边第二项,枚举 x <= y <= z 。
用暴力搜一遍会超时,想到用树状数组。
#include <iostream>
#include <fstream>
#include <cstdio>
#include <sstream>
#include <set>
#include <bitset>
#include <queue>
#include <deque>
#include <stack>
#include <list>
#include <vector>
#include <map>
#include <string>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef set<int> Set;
typedef vector<int> Vec;
typedef set<int>::iterator sIt;
typedef vector<int>::iterator vIt;
#define mem(s,t) (memset(s,t,sizeof(s)))
#define D(v) cout<<#v<<" "<<v<<endl
const int INF=0x7f;
ll mod=1e8+7;
const int N=100005;
ll c[N];//树状数组
int lowbit(int x){
return x&-x;
}
ll sum(int x){
ll summ=0;
while(x>0){
summ+=c[x];
x-=lowbit(x);
}
return summ;
}
void modify(int pos,int num,int n){
while(pos<=n){
c[pos]+=num;
pos+=lowbit(pos);
}
}
int n;
int a[N],b[N];
int d[N],e[N];
int main() {
#ifdef LOCAL
freopen("in.txt","r",stdin);
#endif
int T;scanf("%d",&T);
for(int kase=1;kase<=T;kase++){
mem(c,0);
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
a[i]=abs(a[i]);
b[i-1]=a[i];
}
sort(b,b+n);
int nn=unique(b,b+n)-b;//去除相邻的重复元素,返回去重后最后一个元素的地址
for(int i=1;i<=n;i++){
a[i]=lower_bound(b,b+nn,a[i])-b+1;//返回 ai 排序后的位置: 1 to nn
}
for(int i=n;i>=1;i--){
d[i]=sum(nn)-sum(a[i]-1);
e[i]=sum(nn)-sum(a[i]);
modify(a[i],1,nn);
}
/* for(int i=1;i<=n;i++){ cout<<e[i]<<" "; }cout<<endl; for(int i=1;i<=nn;i++){ cout<<c[i]<<" "; }cout<<endl; */
mem(c,0);
ll ans=0;
for(int i=n;i>=1;i--){
ans+=(ll)e[i]*(e[i]-1)/2-(sum(nn)-sum(a[i]));
ans%=mod;
modify(a[i],d[i],nn);
}
printf("Case #%d: %lld\n",kase,ans);
}
return 0;
}