题面
分析
二分+前缀和优化求解
二分
可以看出来,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;}
}