长安大学第四届ACM-ICPC“迎新杯”程序设计竞赛-重现赛 H - 圣诞节糖果

题目描述

圣诞节临近,彩虹岛的黑心商人𝑐𝑡𝑟的糖果店又开始热闹了起来,热心的𝑠𝑙𝑝来到𝑐𝑡𝑟的店里面帮忙包装糖果。店里面共有𝑛堆糖果,其中第𝑖堆有𝑎𝑖颗糖果,𝑐𝑡𝑟让𝑠𝑙𝑝从中选择两堆糖果,这两堆糖果中每𝑝 颗包装在一起,如果最后还有剩余就归𝑠𝑙𝑝所有了,若两堆不足𝑝个则全部归𝑠𝑙𝑝所有。作为糖果狂热爱好者,𝑠𝑙𝑝当然是想拿走尽量多的糖果,因此他想知道自己最多能够拿走多少糖果。

输入描述:

输入第一行为一个整数𝑇(1 ≤ 𝑇 ≤ 10),表示一共有𝑇组测试数据。
对于每组测试数据:
第一行有两个整数𝑛(2 ≤ 𝑛 ≤ 105), 𝑝(1 ≤ 𝑝 ≤ 109),分别表示糖果堆数和包装后每包糖果的数量。
第二行有𝑛个整数,其中第𝑖个数𝑎𝑖(1 ≤ 𝑎𝑖 ≤ 109)表示第𝑖堆糖果的数量。

输出描述:

对于每组测试数据,输出一个整数𝑥表示𝑠𝑙𝑝能拿走的最多的糖果数目。
示例1

输入

2
4 5
1 4 2 3
4 15
12 19 13 20

输出

4
10

说明

对于第一组样例,𝑠𝑙𝑝选择第一堆和第四堆是最佳选择,会剩余4颗糖果。
对于第二组样例,𝑠𝑙𝑝选择第一堆和第三堆是最佳选择,会剩余10颗糖果。

题解

枚举,二分,排序。

先将每个数对$p$取模,然后排序。枚举第$i$个数字必选,然后可以去二分最大的和不超过$p$的那个数字,以及最大的那个数字。取最大值即可。

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e5 + 10;
int T, n;
long long p;
long long a[maxn];

int main() {
  scanf("%d", &T);
  while(T --) {
    scanf("%d%lld", &n, &p);
    for(int i = 1; i <= n; i ++) {
      scanf("%lld", &a[i]);
      a[i] = a[i] % p;
    }
    sort(a + 1, a + 1 + n);
    long long ans = 0;
    for(int i = 1; i <= n; i ++) {
      long long x = p - a[i] - 1;
      int L = 1, R = n, pos = -1;
      while(L <= R) {
        int mid = (L + R) / 2;
        if(a[mid] <= x) {
          L = mid + 1;
          pos = mid;
        } else {
          R = mid - 1;
        }
      }
      if(pos != -1 && pos > i) {
        ans = max(ans, a[i] + a[pos]);
      }
      if(n > i) {
        ans = max(ans, (a[i] + a[n]) % p);
      }
    }
    printf("%lld\n", ans);
  }
  return 0;
}

  

posted @ 2017-12-21 15:21  Fighting_Heart  阅读(318)  评论(0编辑  收藏  举报