# 最大余数 - 第一课:枚举技巧 - 状压 / 折半 / 尺取法 - 2020 最新版提高组初级课程

题目链接

# 思路

折半 + 二进制枚举

注意 b 数组要排个序~

# 代码

#include <bits/stdc++.h>
using namespace std;
int n,mod;
int a[1000010];
int b[1000010];
int tot;
int find(int x)
{
  int ans=-1;
  int l=0,r=tot-1;
  if(b[r]<=x) {
    return b[r];
  }
  while(l<=r) {
    int mid=(l+r)/2;
    if(b[mid]<=x) {
      ans=b[mid];
      l=mid+1;
    } else {
      r=mid-1;
    }
  }
  return ans;
}
int main() {
  scanf("%d%d",&n,&mod);
  for(int i=0;i<n;i++) {
    scanf("%d",&a[i]);
    a[i]%=mod;
  }
  int m=n/2;
  for(int i=0;i<(1<<m);i++) {
    int tmp=0;
    for(int j=0;j<m;j++) {
      if(i&(1<<j)) {
        tmp=(tmp+a[j])%mod;
      }
    }
    b[tot++]=tmp;
  }
  sort(b,b+tot);
  m=n-(n/2);
  int ans=0;
  for(int i=0;i<(1<<m);i++) {
    int tmp=0;
    for(int j=0;j<m;j++) {
      if(i&(1<<j)) {
        int jj=j+n/2;
        tmp=(tmp+a[jj])%mod;
      }
    }
    int x=find(mod-tmp-1);
    ans=max(ans,(x+tmp));
    if(ans==mod-1) {
      break;
    }
  }
  cout<<ans<<"\n";
  return 0;
}