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

来源:互联网 发布:我的世界砍树与挖矿js 编辑:程序博客网 时间:2024/04/29 17:13

#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 5050using 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 0
原创粉丝点击