2017年ZJUT校赛-Problem B: 平方2——树状数组

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(s1) 种。此时 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;
}
    原文作者:B树
    原文地址: https://blog.csdn.net/Joovo/article/details/69048542
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞