一道比较套路的题,看到数据范围就差很少有想法了吧。git
题目大意:给一个数列和\(m\),在数列任选若干个数,使得他们的和对\(m\)取模后最大spa
取膜最大,好像不能DP/贪心/玄学乱搞啊。\(n\le35\)?果断meet in middlecode
考虑咱们已经搜出了序列前一半的解,那么怎么根据后面的结果合并出结果?it
设咱们如今获得的和为\(x\)(对\(m\)取膜后),咱们令一个数\(y=m-x\),而后在前面的解中查找\(y\)的前驱便可io
接下来进行简单的证实:class
因而咱们每次都二分找出前缀,并取\(max\)便可。数据
CODEsort
#include<cstdio> #include<cctype> #include<algorithm> using namespace std; const int N=40; int a[N],n,m,sum[1<<20],cnt,ans; inline char tc(void) { static char fl[100000],*A=fl,*B=fl; return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++; } inline void read(int &x) { x=0; char ch; while (!isdigit(ch=tc())); while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc())); } inline int find(int x) { int l=1,r=cnt,res; while (l<=r) { int mid=l+r>>1; if (sum[mid]<x) res=sum[mid],l=mid+1; else r=mid-1; } return res; } inline void init(int now,int tot) { if (now>(n>>1)) { sum[++cnt]=tot; return; } init(now+1,(tot+a[now])%m); init(now+1,tot); } inline void DFS(int now,int tot) { if (now>n) { ans=max(ans,tot+find(m-tot)); return; } DFS(now+1,(tot+a[now])%m); DFS(now+1,tot); } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); register int i; read(n); read(m); for (i=1;i<=n;++i) read(a[i]); init(1,0); sort(sum+1,sum+cnt+1); DFS((n>>1)+1,0); return printf("%d",ans),0; }