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 }