标签: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; }
【BZOJ1071】【SCOI2007】组队 利用单调性的双指针
标签:bzoj1071 scoi2007 组队 单调性 双指针
原文地址:http://blog.csdn.net/vmurder/article/details/43407071