背包

题目链接: https://www.nowcoder.com/acm/contest/133/B

  1 /*
  2   题意:V背包容量,n物品个数,m需要装的物品个数,ai,bi价值,大小,求刚好装m个物品时,物品的中位数最大是多少
  3   思路:首先按照价值排序,m个物品分成三组,中位数,小于中位数,和大于中位数的
  4         假设m为奇数,中位数只有一个,于是我们可以处理处前缀装m/2个物品的最小容量,和后缀装m/2个物品的最小容量,然后依次判断以某个点
  5            作为中位数是否满足情况
  6         当m为偶数时,中位数有两个,我们处理前m/2-1个物品前缀和,和后面m/2个物品的后缀和,然后同样枚举中间的一个数,这样中位数就是当前数和
  7            后缀的第一个数,这时需要二分判断后缀和的开始位置,由于后缀和是递增的,这个可以log(n)实现。
  8   时间:2018.07.21
  9 */
 10 #include <bits/stdc++.h>
 11 using namespace std;
 12 
 13 typedef long long LL;
 14 const int MAXN=100005;
 15 const LL MOD7 = 1e9+7;
 16 
 17 struct Node
 18 {
 19     LL a,b;
 20 }node[MAXN];
 21 
 22 
 23 LL f[MAXN];
 24 LL g[MAXN];
 25 int n,m;
 26 LL V;
 27 
 28 int cmp(Node oa,Node ob)
 29 {
 30     return oa.a<ob.a;
 31 }
 32 
 33 void solve()
 34 {
 35     int s=(m-1)/2;
 36     priority_queue<int> q;
 37     LL sum=0;
 38     for (int i=1;i<=s;++i)
 39     {
 40         sum+=node[i].b;
 41         q.push(node[i].b);
 42     }
 43     f[s]=sum;
 44     for (int i=s+1;i<=n;++i)
 45     {
 46         if (s && node[i].b<q.top())
 47         {
 48             sum+=node[i].b-q.top();
 49             q.pop();
 50             q.push(node[i].b);
 51         }
 52         f[i]=sum;
 53     }
 54     while (!q.empty()) q.pop();
 55     sum=0;
 56     LL ans=0;
 57     if (m&1)
 58     {
 59         for (int i=n;i>=n-s+1;--i)
 60         {
 61             sum+=node[i].b;
 62             q.push(node[i].b);
 63         }
 64         g[n-s+1]=sum;
 65         for (int i=n-s;i>=s+1;--i)
 66         {
 67             if (node[i].b<q.top())
 68             {
 69                 sum+=node[i].b-q.top();
 70                 q.pop();
 71                 q.push(node[i].b);
 72             }
 73             g[i]=sum;
 74         }
 75         for (int i=n-s;i>=s+1;--i)
 76         {
 77             // printf("f[%d]=%lld g[%d]=%lld\n",i-1,f[i-1],i+1,g[i+1]);
 78             if (f[i-1]+g[i+1]+node[i].b<=V)
 79             {
 80                 ans = node[i].a;
 81                 break;
 82             }
 83         }
 84     }
 85     else //m&1==0
 86     {
 87         ++s;
 88         for (int i=n;i>=n-s+1;--i)
 89         {
 90             sum+=node[i].b;
 91             q.push(node[i].b);
 92         }
 93         g[n-s+1]=sum;
 94         for (int i=n-s;i>=s;--i)  // i: n-m/2-1 -> m/2
 95         {
 96             if (node[i].b<q.top())
 97             {
 98                 sum+=node[i].b-q.top();
 99                 q.pop();
100                 q.push(node[i].b);
101             }
102             g[i]=sum;
103         }
104         // for (int i=1;i<=n;++i) printf("f[%d]=%lld g[%d]=%lld\n",i,f[i],i,g[i]);puts("");
105         int x;
106         for (int i=s;i<=n-s;++i)
107         {
108             x=i;
109             //二分右边界
110             for (int l=(1<<20);l;l>>=1)
111                 if (x+l<=n-s+1 && f[i-1]+g[x+l]+node[i].b<=V)
112                 x=x+l;
113             if (x!=i)
114                 ans = max(ans, (node[i].a+node[x].a)/2);
115         }
116     }
117     printf("%lld\n",ans);
118 }
119 
120 int main()
121 {
122 #ifndef ONLINE_JUDGE
123     freopen("test2.txt","r",stdin);
124 #endif // ONLINE_JUDGE
125     while (scanf("%lld%d%d",&V,&n,&m)!=-1)
126     {
127         for (int i=1;i<=n;++i)
128         {
129             scanf("%lld%lld",&node[i].a,&node[i].b);
130         }
131         sort(node+1,node+1+n,cmp);
132         solve();
133     }
134     return 0;
135 }
136 /*
137 In [1]:
138 20 5 3
139 3 5
140 5 6
141 8 7
142 10 6
143 15 10
144 
145 Out [1]:
146 8
147 
148 In [2]:
149 3 4 2
150 1 1
151 2 3
152 3 3
153 4 1
154 
155 Out [2]:
156 2
157 
158 
159 */

猜你喜欢

转载自www.cnblogs.com/LeeSongt/p/9346149.html