zoukankan      html  css  js  c++  java
  • CF961E Solution

    题目链接

    题解

    下文将符合题意的数对成为“逆数对”。

    可以发现,\(x=a_i\)的逆数对个数为满足\(i<j\le a_i,a_j\ge i\)\(j\)个数,因为\(j\)的季数需\(\le i\)的最大集数,而其最大集数需\(\ge i\)的季数。对于第一个条件,可以将\(j\)存入树状数组,每次取区间\([i+1,a_i]\)和即可。因为由\(1\)\(n\)遍历\(a\)数组时\(i\)单调递增,可以设数组\(b\)为增序排序后的\(a\),当\(b\)数组当前左端点元素\(\le i\)时便将该元素从树状数组中删除,并将左端点右移。

    #include<bits/stdc++.h>
    #define int long long
    #define lowb(x) x&(-x) 
    using namespace std;
    const int N=2e5+10;
    struct node {int v,id;} b[N];//v:a数组增序排序的值,id:v在a数组中下标
    int t[N],a[N],n; 
    bool cmp(node a,node b) {return a.v<b.v;}
    void add(int x,int d)
    {
    	while(x<=n) {t[x]+=d; x+=lowb(x);}
    }
    int query(int x)
    {
    	int ans=0;
    	while(x) {ans+=t[x]; x-=lowb(x);}
    	return ans;
    }
    signed main()
    {
    	scanf("%lld",&n);
    	for(int i=1;i<=n;i++) 
    	{
    		scanf("%lld",&a[i]); add(i,1);//将j加入树状数组
    		b[i].v=a[i]; b[i].id=i;
    	}
    	sort(b+1,b+n+1,cmp);
    	int pos=0,ans=0;
    	for(int i=1;i<=n;i++)
    	{
    		ans+=max(0ll,query(min(a[i],n))-query(i));//统计答案
    		while(b[++pos].v<=i && pos<=n) add(b[pos].id,-1);//删除不合法a[j]
    		pos--;//当前pos为合法下标,需-1
    	}
    	printf("%lld",ans);
    	return 0;
    }
    
  • 相关阅读:
    《机器学习实战》K近邻算法
    第 4 章 单例模式
    第 3 章 闭包和高阶函数
    第2章 this 、 call 和 apply
    第1章 面向对象的JavaScript
    前言 发展历史
    Linux常用的基本命令
    VLSM
    IP编址和子网划分
    RADIUS操作命令
  • 原文地址:https://www.cnblogs.com/violetholmes/p/14364018.html
Copyright © 2011-2022 走看看