牛客周赛 Round 28 F

F.小红统计区间(hard)

题目链接

Sum[r]-Sum[l]\geq k\ \Rightarrow \ Sum[r]-k\geq Sum[l]\ \Rightarrow \ ans++

Sum[i]\geq k\Rightarrow ans++

Sum[i]为前缀和

  • 枚举右端点看有多少个左端点满足条件,即在一个数轴上找x\leq Sum[i]-kx的个数。可以利用树状数组区间查询,查找1\rightarrow i-1中满足条件的前缀和。具体操作为先查找,再把自身在数轴上对应的数的个数加一。所以统计时没有统计Sum[i]\geq k自身对答案的影响。当前操作为第i位时,则数轴上只记录了1\rightarrow i-1的前缀和。
  • 由于前缀和过大,形成的数轴过长,采用离散化。将所有前缀和由小到大排序并去重,构成新数轴。
  • 由于Sum[l]-k在数轴上可能没有直接映射,所以通过二分找到满足条件的最大的前缀和,转为统计小于等于它的前缀和个数。找不到就不更新ans
  • ans最大会到1e10,会爆int


import java.io.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Scanner;



public class Main{
	static 
	class BIT{
		int size;
		long[] tr;
		public BIT(int n) {
			size=n;
			tr=new long[n+1];
		}
		public int lowbit(int x) {
			return x&(-x);
		}
		public void update(int x) {
			for(int i=x;i<=size;i+=lowbit(i)) {
				tr[i]++;
			}
		}
		public long query(int x) {//区间组合最多1e10,int会爆
			long ans=0;
			for(int i=x;i>0;i-=lowbit(i)) {
				ans+=tr[i];
			}
			return ans;
		}
	}
	public static void main(String[] args) throws IOException{
		Scanner input=new Scanner(System.in);
		int n=input.nextInt();
		long k=input.nextLong();
		long ans=0;
		long[] Sum=new long[n];//用于离散化的前缀和
		long[] pre=new long[n];//保留原本的前缀和
		Sum[0]=input.nextLong();
        if(Sum[0]>=k)ans++;
		pre[0]=Sum[0];
		for(int i=1;i=k)ans++;
			pre[i]=Sum[i];
		}
		Arrays.sort(Sum);
		HashMap hs=new HashMap();
		int cnt=0;
		long[] Qu=new long[n+1];//离散后数轴每位对应的前缀和
		for(int i=0;i>1;
				if(Qu[mid]<=y) { 
					id=mid;
					l=mid+1;
				}
				else r=mid-1;
			}
			if(id!=-1)ans+=Tr.query(hs.get(Qu[id]));
			Tr.update(hs.get(pre[i]));
		}
		System.out.println(ans);
	}
	
}

你可能感兴趣的:(算法,数据结构)