【BZOJ1071】【SCOI2007】组队 利用单调性的双指针

#include <stdio.h>
int main()
{
	puts("转载请注明出处谢谢");
	puts("http://blog.csdn.net/vmurder/article/details/43407071");
}


Orz Xs酱  http://www.cnblogs.com/rausen/p/4007292.html

题解:O(n*n)


首先我们先外圈枚举一个最小权值一

然后内圈再枚举一个最小权值二


然后每次外圈枚举完了就重置一下双指针,

每次内圈枚举的时候右指针右移把总条件符合的加进去,其中第二个权值符合枚举条件的计数。

然后左指针右移把第一个权值不符合的清出去,其中第而个权值符合枚举条件的计数。


因为单调性问题,所以不会有l>r 的情况(第一权值不符合的在右指针右移时,第一权值贡献为负


代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 5050
using namespace std;
int n,A,B,C;
int Max,Min,l,r,cnt,ans;
struct KSD
{
	int h,v,s;
	void keep(){s=A*h+B*v;}
}x[2][N];
inline bool cmph(const KSD &a,const KSD &b){return a.h<b.h;}
inline bool cmps(const KSD &a,const KSD &b){return a.s<b.s;}
inline bool check(int id,int d)
{return x[id][d].v<=Max&&x[id][d].v>=Min;}
int main()
{
	freopen("test.in","r",stdin);
	int i,j,k;
	scanf("%d%d%d%d",&n,&A,&B,&C);
	for(i=1;i<=n;i++)
	{
		scanf("%d%d",&x[0][i].h,&x[0][i].v);
		x[0][i].keep(),x[1][i]=x[0][i];
	}
	sort(x[0]+1,x[0]+n+1,cmph);
	sort(x[1]+1,x[1]+n+1,cmps);
	for(i=1;i<=n;i++) // 枚举v最小值
	{
		Min=x[0][i].v,Max=Min+C/B;
		l=r=cnt=0;
		for(j=1;j<=n;j++) // 枚举h最小值
		{
			while(r<n&&x[1][r+1].s-A*x[0][j].h-B*x[0][i].v<=C)
				cnt+=check(1,++r);//按照s排序取出可行队员
			while(l<n&&x[0][l+1].h<x[0][j].h)cnt-=check(0,++l);
			ans=max(ans,cnt);//再干掉一些当初入队时计数了的队员
		}
	}
	printf("%d\n",ans);
	return 0;
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值