洛谷聪明的质监员【JAVA实现】

题面

分析


二分+前缀和优化求解

二分

可以看出来,W越大,被选上的矿石越少,则对应的Y值越小。
随着W的增大,Y值减小。 这就单调性我们可以在二分过程中求解与s相差最小的Y值,

前缀和

在计算Y值时需要操作区间和,通过前缀和可以优化时间复杂度。
设L[i],R[i]为需要操作区间的左右端点。pren[i]为0到第i个被选中的矿石数量,
prev[i]为到第i个为止被选中的 矿石的总价值。
则Yj=(pren[R[j]]-pren[L[j]-1])*(prev[R[j]]-prev[L[j]-1])。(L[j]-1,是因为包含左端点)

PS:注意开long。初始化答案(ans)一定要大。

代码


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.Arrays;
import java.util.Scanner;

public class Main{

	public static class off{
		private int w;
		private int v;
	}
	static long sum,k;
	static int n,m;
	static off a[];//存储矿石元素
	static int l[],r[];//区间端点
	static long  pren[],prev[];//前缀和需要
	public static void main(String[] args) throws IOException {
		n=nextInt();m=nextInt();
		 k=(long)nextDouble();
		 pren=new long[n+1];
		 a=new off[n+1];prev=new long[n+1];
		l=new int[m+1];
		r=new int[m+1];
		int mx=-1;
		int mi=2147483647;
		for (int i = 1; i <=n; i++) {
			a[i]=new off();
			a[i].w=nextInt();
			a[i].v=nextInt();
			mi=Math.min(mi,a[i].w);
			mx=Math.max(mx,a[i].w);
		}
		for (int i = 1; i <=m; i++) {
			l[i]=nextInt();
			r[i]=nextInt();	
		}
		int left=mi-1;int right=mx+2,mid;
		long ans=99999999999999L;//初始化,用于更新
		while(left<=right) {	//二分
			mid=(left+right)>>1;
		if(check(mid)) {
			left=mid+1;
		}else {
			right=mid-1;
		}
		sum=Math.abs(sum);
			if(sum<ans) {
				ans=sum;
			}
		}
		System.out.println(ans);	//输出
	}
	public static boolean check(int d) { //检验答案
		Arrays.fill(pren,0);
		Arrays.fill(prev,0);
		 sum=0;
		for (int i = 1; i <=n; i++) {
			if(a[i].w>=d) {
				pren[i]=pren[i-1]+1;
				prev[i]=prev[i-1]+a[i].v;
			}else {
				pren[i]=pren[i-1];
				prev[i]=prev[i-1];
			}
		}
		for (int i =1; i <=m; i++) {
			sum+=(long)(pren[r[i]]-pren[l[i]-1])*(prev[r[i]]-prev[l[i]-1]);
		}
		sum-=k;
		if(sum>0) return true;
		return false;
	}
	//-------------快读板子-------------
	public static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in),32768));
	public static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
	public static double nextDouble() throws IOException{ in.nextToken(); return in.nval; }
	public static float nextFloat() throws IOException{ in.nextToken(); return (float)in.nval; }
	public static int nextInt() throws IOException{ in.nextToken(); return (int)in.nval; }
	public static String next() throws IOException{ in.nextToken(); return in.sval;}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值