• 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;
    }
    
  • 相关阅读:
    oracle 第12章 归档日志文件
    oracle 第09章 参数文件
    oracle 第11章 重做日志文件
    oracle 第10章 控制文件
    oracle 第14章 表空间管理
    linux yum源配置
    oracle 第08章 用户、权限、角色管理
    oracle 第07章 网络配置管理
    第二阶段冲刺-06
    第二阶段冲刺-05
  • 原文地址:https://www.cnblogs.com/violetholmes/p/14364018.html
Copyright © 2020-2023  润新知