[SCOI2007]组队

嘟嘟嘟

这题有人说部分分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踢出。

 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 }
View Code
原文地址:https://www.cnblogs.com/mrclr/p/9536685.html