1. 程式人生 > >1071: [SCOI2007]組隊

1071: [SCOI2007]組隊

1071: [SCOI2007]組隊

https://lydsy.com/JudgeOnline/problem.php?id=1071

分析:

  dp+單調性。

  A*(hi–minH)+B*(si–minV)<=C

  Ahi+Bsi<=C+A*minH+B*minV

  如果列舉一個minH,和一個minV的話,那麼把陣列按Ahi+Bsi排序後,這個陣列就具有單調性了。

  這裡面的人不一定滿足si>=minV和hi>=minH。先固定一個minV,然後把所有大於等於minV的取出來。這樣滿足了第一個限制。然後列舉minH的時候會由於minH的增加而導致小於了minH,可以把所有加入的放進小根堆裡,然後不斷彈出不合法的。這樣複雜度是$n^2logn$在bzoj上過不了的(luogu上開O2可以過)

  考慮列舉的時候先si>=minV,那麼就有A*(hi-minH)<=C+B*minV-B*si,因為要hi>=minH,所0<=左式<=右式,所以C+B*minV-B*si>=0,得到si<=C/B+mv這樣還沒有滿足左式>=0的條件,所以si應該滿足minV<=si<=C/B+minV。

  這樣依然沒有滿足左式>=0的條件。考慮減去這些不合法的。這裡只需要按h從i小到大的掃描所有人,如果這個si是合法的,那麼減去。

  這樣減是否會減到一些沒有列舉過的?

  

就是列舉下面的序列的時候,是否列舉到上面的排列的後面去。

是不會的。

下面序列的滿足,hi<=minH,si<=C/B+minV,所以A*hi+B*si最大是A*minH+B*minV+C,剛好到第一個序列的位置。

程式碼:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<cmath>
 6 #include<cctype>
 7 #include<set>
 8 #include<queue>
 9
#include<vector> 10 #include<map> 11 using namespace std; 12 typedef long long LL; 13 14 inline int read() { 15 int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; 16 for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; 17 } 18 19 const int N = 100005; 20 21 struct Node{ 22 int h, v; LL tot; 23 }s[N], mv[N], mh[N]; 24 25 bool cmp1(const Node &A, const Node &B) { 26 return A.tot < B.tot; 27 } 28 bool cmp2(const Node &A, const Node &B) { 29 return A.h < B.h; 30 } 31 bool cmp3(const Node &A, const Node &B) { 32 return A.v < B.v; 33 } 34 35 int main() { 36 int n = read(); LL A = read(), B = read(), C = read(); 37 for (int i = 1; i <= n; ++i) { 38 s[i].h = read(), s[i].v = read(); s[i].tot = A * s[i].h + B * s[i].v; 39 mv[i] = mh[i] = s[i]; 40 } 41 sort(s + 1, s + n + 1, cmp1); 42 sort(mh + 1, mh + n + 1, cmp2); 43 sort(mv + 1, mv + n + 1, cmp3); 44 45 int ans = 0; 46 for (int i = 1; i <= n; ++i) { 47 int p1 = 1, p2 = 1, cnt = 0; 48 LL minv = mv[i].v, limv = minv + C / B; 49 for (int j = 1; j <= n; ++j) { 50 LL minh = mh[j].h, limtot = C + A * minh + B * minv; 51 while (p1 <= n && s[p1].tot <= limtot) { 52 if (s[p1].v >= minv && s[p1].v <= limv) cnt ++; 53 p1 ++; 54 } 55 while (p2 <= n && mh[p2].h < minh) { 56 if (mh[p2].v >= minv && mh[p2].v <= limv) cnt --; 57 p2 ++; 58 } 59 ans = max(ans, cnt); 60 } 61 } 62 cout << ans; 63 return 0; 64 }
線性
 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<cmath>
 6 #include<cctype>
 7 #include<set>
 8 #include<queue>
 9 #include<vector>
10 #include<map>
11 using namespace std;
12 typedef long long LL;
13 
14 inline int read() {
15     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
16     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
17 }
18 
19 const int N = 100005;
20 
21 struct Node{
22     int h, v; LL tot;
23 }s[N], mv[N], mh[N];
24 
25 bool cmp1(const Node &A, const Node &B) {
26     return A.tot < B.tot; 
27 }
28 bool cmp2(const Node &A, const Node &B) {
29     return A.h < B.h;
30 }
31 bool cmp3(const Node &A, const Node &B) {
32     return A.v < B.v;
33 }
34 priority_queue<int, vector<int>, greater<int> > q; 
35 int main() {
36     int n = read(); LL A = read(), B = read(), C = read();
37     for (int i = 1; i <= n; ++i) {
38         s[i].h = read(), s[i].v = read(); s[i].tot = A * s[i].h + B * s[i].v;
39         mv[i] = mh[i] = s[i];
40     }
41     sort(s + 1, s + n + 1, cmp1);
42     sort(mh + 1, mh + n + 1, cmp2);
43     sort(mv + 1, mv + n + 1, cmp3);
44     
45     int ans = 0;
46     for (int i = 1; i <= n; ++i) {
47         int p = 1, cnt = 0;
48         LL minv = mv[i].v;
49         for (int j = 1; j <= n; ++j) {
50             LL minh = mh[j].h, limtot = C + A * minh + B * minv;
51             while (p <= n && s[p].tot <= limtot) {
52                 if (s[p].v >= minv && s[p].h >= minh) cnt ++, q.push(s[p].h);
53                 p ++;
54             }
55             while (!q.empty() && q.top() < minh) cnt--, q.pop();
56             ans = max(ans, cnt);
57         }
58     }
59     cout << ans;
60     return 0;
61 }