1071: [SCOI2007]組隊
阿新 • • 發佈:2018-11-29
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 }堆