zoukankan      html  css  js  c++  java
  • [Usaco2011]Above the Median

    知识点前置

    ·树状数组

    题面来源

    https://www.luogu.com.cn/problem/P3031

    题目大意

    给你一个长度为 (n) 序列,求出满足以下条件的子序列个数有多少个:
    中位数大于给出的 (k)

    解题方法

    自己想了半天才打出来
    --------------------分割线--------------------
    因为我们要求的区间中,每个数 (a_i)对于 (k)来说,只有两种情况:

    [a_i>=k||a_i<k ]

    那么,我们把(a_i>=k)这个位置打成1,而(a_i<k)打成-1,那么就变成了这样(k=6时):

    num 10 5 6 2
    a 1 -1 1 -1

    然后我们再把这个a丢到树状数组里去做前缀和,就得到了

    sum 1 0 1 0

    这个时候,我们就可以一遍一遍的查在(i)这个位置之前有多少个数字sum比sum[i]小,最后整合相加得到答案
    注意:前缀和sum可能为负数,所以在搜的时候,把每个位置保险起见加上一个n+1,不影响结果

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn=200005;//maxn开两倍
    
    long long n,x,ans;
    long long a[maxn],num[maxn],sum[maxn];
    
    void add(int x,int vol)
    {
    	while(x<=n+n+1)
    	{
    		sum[x]+=vol;
    		x+=(x & -x);
    	}
    }
    
    int query(int x)
    {
    	int ret=0;
    	while(x)
    	{
    		ret+=sum[x];
    		x-=(x & -x);
    	}
    	return ret;
    }
    
    int main()	
    {
    	scanf("%lld%lld",&n,&x);
    	a[0]=0;
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%lld",&num[i]);
    		if(num[i]>=x)a[i]=a[i-1]+1;
    		else		 a[i]=a[i-1]-1;
    	}
    	add(n+1,1);//预处理0的位置
    	for(int i=1;i<=n;i++)
    	{
    		ans+=query(a[i]+n+1); 
    		add(a[i]+n+1,1);
    	}
    	printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    redis使用lua脚本遇到的问题
    redis使用scan count 返回数量不准确
    window系统下搭建本地的NuGet Server
    windows10使用docker发布.netcore程序
    windows10使用docker安装mysql
    windows10搭建redis4.0集群
    windows10配置redis主从复制
    windows10安装redis4.0
    mysql 共享排他锁
    mysql drop表以后恢复数据
  • 原文地址:https://www.cnblogs.com/jyx-txzr/p/13234261.html
Copyright © 2011-2022 走看看