补牛客多校的这道题:https://ac.nowcoder.com/acm/contest/882/F 中途相遇做法补自闭了(算贡献那里极其复杂,其实有更好的方法),于是找到了下面这个简单的了。
【题目】
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output
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 .
Examples
input
Copy
4 4
5 2 4 1
output
Copy
3
input
Copy
3 20
199 41 299
output
Copy
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个数,让你任意选取几个数使得他们的和模m下是最大的。
【题解】
(感觉看到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 <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6;
ll a[N],b[N],c[N];
int n;
ll m;
int cnt1,cnt2;
void dfs(int id,ll sum,int ty)
{
sum%=m;
if(ty==1&&id==n/2+1)
{
a[++cnt1]=sum;
return ;
}
else if(ty==2&&id==n+1)
{
b[++cnt2]=sum;
return ;
}
dfs(id+1,sum+c[id],ty);
dfs(id+1,sum,ty);
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;++i) {
scanf("%d",&c[i]);
}
dfs(1,0,1);
dfs(n/2+1,0,2);
ll ans=0;
sort(b+1,b+1+cnt2);
for(int i=1;i<=cnt1;++i)
{
int id=lower_bound(b+1,b+1+cnt2,m-a[i])-b;
--id;
ans=max(ans,a[i]+b[id]);
}
cout<<ans<<endl;
return 0;
}