COGS 859. 数列

/*
先来说一下第一眼看到想出的奇葩方法23333..
找每个数左右有几个比他小的
前几天刚学了区间第k小的求法
然后...
枚举中间的那个点 对于左区间 二分找到他是第几大 右区间同理
然后  *起来
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 50010
#define maxm 50010*18*5
#define ll long long
using namespace std;
ll n,cnt,root[maxn],order[maxn],a[maxn],ans;
struct node{
    ll lc,rc,sum;
}t[maxm];
ll init(){
    ll x=0;char s=getchar();
    while(s<‘0‘||s>‘9‘)s=getchar();
    while(s>=‘0‘&&s<=‘9‘){x=x*10+s-‘0‘;s=getchar();}
    return x;
}
ll Build(ll S,ll L,ll R){
    ll k=++cnt;t[k].sum=S;
    t[k].lc=L;t[k].rc=R;
    return k;
}
void Insert(ll &root,ll pre,ll pos,ll l,ll r){
    root=Build(t[pre].sum+1,t[pre].lc,t[pre].rc);
    if(l==r)return;
    ll mid=l+r>>1;
    if(pos<=mid)Insert(t[root].lc,t[pre].lc,pos,l,mid);
    else Insert(t[root].rc,t[pre].rc,pos,mid+1,r);
}
ll Query(ll L,ll R,ll k,ll l,ll r){
    if(l==r)return l;
    ll sum=t[t[R].lc].sum-t[t[L].lc].sum;
    ll mid=l+r>>1;
    if(k<=sum)return Query(t[L].lc,t[R].lc,k,l,mid);
    else return Query(t[L].rc,t[R].rc,k-sum,mid+1,r);
}
int main()
{
    //freopen("queueb.in","r",stdin);
    //freopen("queueb.out","w",stdout);
    n=init();
    for(ll i=1;i<=n;i++){
        a[i]=init();
        order[i]=a[i];
    }
    sort(order+1,order+1+n);
    ll num=n,pos,l,r,x,s1,s2;
    for(ll i=1;i<=n;i++){
        pos=lower_bound(order+1,order+1+n,a[i])-order;
        Insert(root[i],root[i-1],pos,1,num);
    }
    for(ll i=1;i<=n;i++){
        x=a[i];s1=s2=0;
        l=1;r=i;
        while(l<=r){
            ll mid=l+r>>1;
            pos=Query(root[0],root[i],mid,1,num);
            if(order[pos]<x){
                s1=mid;l=mid+1;
            }
            else r=mid-1;
        }
        l=1;r=n-i+1;
        while(l<=r){
            ll mid=l+r>>1;
            pos=Query(root[i-1],root[n],mid,1,num);
            if(order[pos]<x){
                s2=mid;l=mid+1;
            }
            else r=mid-1;
        }
        ans+=s1*s2;
    }
    printf("%lld\n",ans);
    return 0;
}
/*
其实求左右各有几个比他小的 可以用树状数组
逆序对是求左边几个比他大的这个一样啊
注意右边的时候离散化排序和左边不一样
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 50010
#define ll long long
using namespace std;
int n,b[maxn],t[maxn],l[maxn],r[maxn];
ll ans;
struct node{
    int o,x;
}a[maxn];
int init(){
    int x=0;char s=getchar();
    while(s<‘0‘||s>‘9‘)s=getchar();
    while(s>=‘0‘&&s<=‘9‘){x=x*10+s-‘0‘;s=getchar();}
    return x;
}
int cmp1(const node &a,const node &b){
    if(a.x==b.x)return a.o>b.o;
    return a.x<b.x;
}
int cmp2(const node &a,const node &b){
    if(a.x==b.x)return a.o<b.o;
    return a.x<b.x;
}
void Add(int pos,int data){
    while(pos<=n){
        t[pos]+=data;
        pos+=pos&(-pos);
    }
}
int find(int pos){
    int r=0;
    while(pos){
        r+=t[pos];
        pos-=pos&(-pos);
    }
    return r;
}
int main()
{
    freopen("queueb.in","r",stdin);
    freopen("queueb.out","w",stdout);
    n=init();
    for(int i=1;i<=n;i++){
        a[i].x=init();
        a[i].o=i;
    }
    sort(a+1,a+1+n,cmp1);
    for(int i=1;i<=n;i++)
        b[a[i].o]=i;
    for(int i=1;i<=n;i++){
        Add(b[i],1);
        l[i]=find(b[i]-1);
    }
    memset(t,0,sizeof(t));
    sort(a+1,a+1+n,cmp2);
    for(int i=1;i<=n;i++)
        b[a[i].o]=i;
    for(int i=n;i>=1;i--){
        Add(b[i],1);
        r[i]=find(b[i]-1);
    }
    for(int i=1;i<=n;i++)
        ans+=(ll)l[i]*r[i];
    printf("%lld\n",ans);
    return 0;
}
时间: 2024-10-11 08:32:47

COGS 859. 数列的相关文章

COGS 2638. 数列操作ψ 线段树

传送门 : COGS 2638. 数列操作ψ 线段树 这道题让我们维护区间最大值,以及维护区间and,or一个数 我们考虑用线段树进行维护,这时候我们就要用到吉司机线段树啦 QAQ 由于发现若干次and,or之后,如果数据分布均匀,那么几乎所有的数在若干次操作后都会变成同一个数 因为我们的and操作中的0位,以及or操作当中的1位,都是可以把整个区间的那一二进制位重置为相同的 我们考虑利用这一个性质 如果我们直接维护一个区间内的值是否是相同的,那么效果会差很多. 我们发现我们在进行and操作的时

COGS——C66. [HAOI2004模拟] 数列问题

http://www.cogs.pro/cogs/problem/problem.php?pid=66 ★☆   输入文件:dfs3.in   输出文件:dfs3.out   简单对比 时间限制:1 s   内存限制:128 MB 问题描述试编程将 1 至 N ( N ≤ 15 )的自然数序列 1 , 2 , … , N 重新排列,使任意相邻两数之和为素数.例如 N=3 时有两种排列方案 123 . 321 满足要求. [输入格式] 输入文件:dfs3.in 第一行:一个整数n(1<=n<=1

数据结构(Splay平衡树):COGS 339. [NOI2005] 维护数列

339. [NOI2005] 维护数列 ★★★★☆   输入文件:seq2005.in   输出文件:seq2005.out   简单对比 时间限制:3 s   内存限制:256 MB [问题描述] 请写一个程序,要求维护一个数列,支持以下 6 种操作:(请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格) 操作编号 输入文件中的格式 说明 1.  插入 INSERT_posi_tot_c1_c2_..._ctot 在当前数列的第 posi 个数字后插入 tot 个数字:c1, c2,

cogs——66. [HAOI2004模拟] 数列问题

66. [HAOI2004模拟] 数列问题 本以为会TLE,可... dfs水题(很基础) #include<bits/stdc++.h> using namespace std; int x,shu[20],ans; bool vis[20]; void print() { for(int i=1; i<=x; i++) printf("%d ",shu[i]); puts(""); ++ans; return; } bool tp(int px

cogs 2632. [HZOI 2016] 数列操作d

2632. [HZOI 2016] 数列操作d ★★★   输入文件:segment.in   输出文件:segment.out   简单对比时间限制:3 s   内存限制:512 MB [题目描述] 一个长度为n的序列,一开始序列数的权值都是0,有m次操作 支持两种操作: 1 L R x,给区间[L,R]内位置为pos的数加上(pos-L)*x 0 L R,查询区间[L,R]内的权值和 最终答案对109+7取模. [输入格式] 第一行两个数n,m,表示序列长度和操作次数 接下来m行,每行描述一

CodeForces E. Lucky Array 幸运数列

CodeForces    E. Lucky Array  幸运数列 Petya loves lucky numbers. Everybody knows that lucky numbers are positive integers whose decimal representation contains only the lucky digits 4 and 7. For example, numbers 47, 744, 4 are lucky and 5, 17, 467 are n

[HEOI2015]公约数数列

公约数数列 [问题描述] 设计一个数据结构. 给定一个正整数数列 a_0, a_1, ...,a_{n - 1},你需要支持以下两种操作: 1. MODIFY id x: 将 aid 修改为 x. 2. QUERY x: 求最小的整数 p (0 <= p < n),使得 gcd(a_0,a_1, ..., a_p) * XOR(a_0, a_1, ..., a_p) = x. 其中 XOR(a_0, a_1, ..., a_p) 代表 a_0, a_1, ..., a_p 的异或和,gcd表示

cogs 36.求和问题

36. 求和问题 ★   输入文件:sum.in   输出文件:sum.out   简单对比时间限制:1.2 s   内存限制:128 MB [问题描述] 在一个长度为n的整数数列中取出连续的若干个数,并求它们的和. [输入格式] 输入由若干行组成,第一行有一个整数n    第二行有n个整数    第三行有一个整数m    下面m行,每行两个整数i与j(i<=j),表示求和的起始和终止位置. [输出格式] 输出有m行, 每行一个整数,表示这个数段数列的和. [输入样例] 输入文件 82 3 4

用递归和非递归的方法输出斐波那契数列的第n个元素(C语言实现)

费波那契数列(意大利语:Successione di Fibonacci),又译为费波拿契数.斐波那契数列.费氏数列.黄金分割数列. 在数学上,费波那契数列是以递归的方法来定义: {\displaystyle F_{0}=0} {\displaystyle F_{1}=1} {\displaystyle F_{n}=F_{n-1}+F_{n-2}}(n≧2) 用文字来说,就是费波那契数列由0和1开始,之后的费波那契系数就是由之前的两数相加而得出.首几个费波那契系数是: 0, 1, 1, 2, 3