Discription
You are given an array a consisting of n integers, and additionally an integer m. You have to choose some sequence of indices b1, b2, ..., bk (1 ≤ b1 < b2 < ... < bk ≤ n) in such a way that the value of is maximized. Chosen sequence can be empty.
Print the maximum possible value of .
Input
The first line contains two integers n and m (1 ≤ n ≤ 35, 1 ≤ m ≤ 109).
The second line contains n integers a1, a2, ..., an (1 ≤ ai ≤ 109).
Output
Print the maximum possible value of .
Example
4 4
5 2 4 1
3
3 20
199 41 299
19
Note
In the first example you can choose a sequence b = {1, 2}, so the sum is equal to 7 (and that's 3 after taking it modulo 4).
In the second example you can choose a sequence b = {3}.
(感觉看到n<=35的第一反应已经是折半搜索了hhh)
显然可以先搜出前n/2个数和后面剩的数可以得到的所有子集(包括空集)的结果(对m取模后)。
然后答案肯定就是从前面选一个子集,后面再选一个子集,把两个拼起来。
假设我们在前n/2中选的子集的权值是s,那么怎么在后面的数中找最优子集呢?
假设我们在后面的数中找的子集的权值是p,那么有两种情况:
1.s+p<m
2.m<=s+p<2*m
对于第一种情况,我们找到<m-s的最大的p即可;
对于第二种情况,我们找到最大的p即可(肯定得减掉一个m,所以p肯定是越大越好)
#include<iostream> #include<cstdio> #include<cstdlib> #include<iostream> #include<algorithm> #include<cmath> #define ll long long #define maxn 500005 using namespace std; int a[maxn],n,m,b[maxn]; int num[105],tot,haf,ha; int ans=0; void dfs1(int x,int sum){ if(sum>=ha) sum-=ha; if(x==haf){ a[++n]=sum; return; } dfs1(x+1,sum); dfs1(x+1,sum+num[x+1]); } void dfs2(int x,int sum){ if(sum>=ha) sum-=ha; if(x==tot){ b[++m]=sum; return; } dfs2(x+1,sum); dfs2(x+1,sum+num[x+1]); } int main(){ scanf("%d%d",&tot,&ha); for(int i=1;i<=tot;i++){ scanf("%d",num+i); if(num[i]>=ha) num[i]-=num[i]/ha*ha; } haf=tot>>1; dfs1(0,0); dfs2(haf,0); sort(a+1,a+n+1); sort(b+1,b+m+1); for(int i=1;i<=n;i++){ int pos=lower_bound(b+1,b+m+1,ha-a[i])-b; ans=max(ans,a[i]+b[pos-1]); ans=max(ans,a[i]+b[m]-ha); } printf("%d ",ans); return 0; }