题目链接: 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 */