这题有人说部分分O(n3)暴力,然而我暴力都没写过,调了半天也没用……还是看题解吧
首先,咱把A * ( h – minH ) + B * ( s – minS ) <= C 变个型,得到 A * h + B * s - C <= A * minH + B * minS. 令 sum = A * h + B * s - C,如果我们把所有球员按sum排序,就能保证取球员的时候是单调的,如果 i 能取,则 j (j < i) 一定能取。
然后我们第一层循环枚举minS,第二层循环枚举minH,然后设两个指针L, R,表示当前符合sum <= A * minH + B * minS的区间,但同时我们还要保证h >= minH && s >= minS,而且根据h >= minH还要保证,s <= minS + C / B.于是就有一个很【强】的做法,我们先把符合的条件的s添加进去,再把队列中不符合条件的h踢出。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 #include<cstdlib> 7 #include<vector> 8 #include<queue> 9 #include<stack> 10 #include<cctype> 11 using namespace std; 12 #define enter puts("") 13 #define space putchar(' ') 14 #define Mem(a) memset(a, 0, sizeof(a)) 15 typedef long long ll; 16 typedef double db; 17 const int INF = 0x3f3f3f3f; 18 const db eps = 1e-8; 19 const int maxn = 5e3 + 5; 20 inline ll read() 21 { 22 ll ans = 0; 23 char ch = getchar(), last = ' '; 24 while(!isdigit(ch)) last = ch, ch = getchar(); 25 while(isdigit(ch)) ans = (ans << 3) + (ans << 1) + ch - '0', ch = getchar(); 26 if(last == '-') ans = -ans; 27 return ans; 28 } 29 inline void write(ll x) 30 { 31 if(x < 0) putchar('-'), x = -x; 32 if(x >= 10) write(x / 10); 33 putchar(x % 10 + '0'); 34 } 35 36 int n; 37 ll A, B, C; 38 struct Node 39 { 40 int h, s; ll sum; 41 }Sum[maxn], H[maxn], S[maxn]; 42 bool cmp1(Node a, Node b) {return a.sum < b.sum;} 43 bool cmp2(Node a, Node b) {return a.h < b.h;} 44 bool cmp3(Node a, Node b) {return a.s < b.s;} 45 46 int ans = 0; 47 48 int main() 49 { 50 n = read(); A = read(); B = read(); C = read(); 51 for(int i = 1; i <= n; ++i) 52 { 53 Sum[i].h = read(), Sum[i].s = read(); Sum[i].sum = (ll)A * Sum[i].h + (ll)B * Sum[i].s - C; 54 H[i].h = Sum[i].h; H[i].s = Sum[i].s; H[i].sum = Sum[i].sum; 55 S[i].h = Sum[i].h; S[i].s = Sum[i].s; S[i].sum = Sum[i].sum; 56 } 57 sort(Sum + 1, Sum + n + 1, cmp1); 58 sort(H + 1, H + n + 1, cmp2); 59 sort(S + 1, S + n + 1, cmp3); 60 for(int i = 1; i <= n; ++i) //枚举minS 61 { 62 int L = 0, R = 0, cnt = 0; 63 ll Mins = S[i].s; 64 ll Lims = Mins + C / B; 65 for(int j = 1; j <= n; ++j) //枚举minH 66 { 67 ll Limsum = A * H[j].h + B * Mins; 68 while(R < n && Sum[R + 1].sum <= Limsum) //合法区间,但不能保证s,h符合 69 { 70 R++; 71 if(Mins <= Sum[R].s && Sum[R].s <= Lims) cnt++; //符合条件的s 72 } 73 while(L < n && H[L + 1].h < H[j].h) //维护合法区间左端点 74 { 75 L++; 76 if(Mins <= H[L].s && H[L].s <= Lims) cnt--; //踢出不符合的h 77 //因为[L, R]中可能有cnt之外的,所以要判断哪些属于cnt,踢出时再cnt-- 78 } 79 ans = max(ans, cnt); 80 } 81 } 82 write(ans); enter; 83 return 0; 84 }