P1493 分梨子

题目描述

题目传送门

思路

我们常规的思路就是:枚举a0,b0(n^2),然后再暴力统计一下(n),总的O(n^3)。

But    (1<=N<=2000)

 所以肯定会TLE的。

那么我们就要想如何把时间复杂度降为n^2.
首先看限制条件:C1*(Ai-A0)+C2*(Bi-B0)≤C3,为了方便验证,把它变形为:  

C1*Ai+C2*Bi-  C3<=C1*A0+C2*B0(为了在预处理的时候不受A0,B0两个变量的影响)

不等式的前面部分仅与i号梨子有关,所以我们把每个梨子的此值存下来,记为d[i]。再把Bi存下来,记为c[i]。记下c,d的梨子编号。
将c,d排序后,枚举A0,在枚举B0,但是此时的B0换成了c[i],是有顺序的。
基于这个顺序,我们可以得到优化:在c[i]从小到大递增的过程中,我们不必每次都把每个梨子验证一次,而可以借助已经算过的值。

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define maxn 2005
struct node {
	int x,id;
} c[2005],d[2005];
bool cmp(node zyl,node pyt) {
	return zyl.x<pyt.x;
}
int n,c1,c2,c3,a[2005],b[2005],cnt[2005],ans;
signed main() {
	cin>>n>>c1>>c2>>c3;
	for(int i=1; i<=n; i++) {
		cin>>a[i]>>b[i];
		c[i].id=d[i].id=i;//保存编号 
		c[i].x=b[i];//保存a[i],b[i]; 
		d[i].x=a[i]*c1+b[i]*c2-c3;//记录公式的值 
	}
	sort(c+1,c+n+1,cmp);
	sort(d+1,d+n+1,cmp);
	//以下几乎为纯暴力、枚举A0,B0就完事 
	for(int i=1; i<=n; i++) { //枚举A0
		int k=0,sum=0;
		memset(cnt,0,sizeof(cnt));//cnt用来记录该甜度被计算了几次
		for(int j=1; j<=n; j++) { //枚举c[j](B0)
			//因为c[j]递增,所以前面能够满足限制的d值在c[j]增加后仍然满足,所以不必再从1到n把d验证一遍,从而达到优化
			while(k<=n&&d[k].x<=a[i]*c1+c[j].x*c2) { //如果d[k]满足限制
				if(a[d[k].id]>=a[i]&&b[d[k].id]>=c[j].x) { //看d[k]原来的a,b是否大于等于最小值
					sum++;//选一个梨子
					cnt[b[d[k].id]]++;//此b值算了一次
				}
				k++;
			}
			sum-=cnt[c[j-1].x];//减去b值已经小于最小值的梨子,因为c排过序,所以减去c[j-1]足矣
			cnt[c[j-1].x]=0;//如果c[j]==c[j-1]可能会重复减
			ans=max(ans,sum);
		}
	}
	cout<<ans;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值