10527
简单题。
对
给出一种考场上想出的构造方式:维护两个集合
接下来证明这么做是对的:考虑对于
接下来我们考虑如何计算最小值。用 bitset 维护当前所有值域中的值是否可以作为一种方案的答案,即
但是值域达到了
记得加滚动数组。
原题解供喷:
容易发现每次就是对 bitset 左移右移或一下然后暴力做不超过 $5000$ 的部分,再加上打乱优化+开小 bitset 即可通过。
具体地,每次 $dp_{i,j+a_i} = dp_{i,j+a_i} \operatorname{or} dp_{i-1,j}$ 直接维护,$dp_{i,|j-a_i|} = dp_{i,|j-a_i|} \operatorname{or} dp_{i-1,j}$ 拆成 $j\ge a_i$(直接 bitset 移位维护)和 $j<a_i$(不超过 $5000$,直接暴力)。
#include <bits/stdc++.h>
using namespace std;
constexpr int maxn=1e4+9;
int a[maxn],n;
bitset<(1<<20)> x[2];
int main()
{
srand(time(0));
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%d",a+i);
random_shuffle(a+1,a+n+1);
x[0].set(0);
for(int i=1;i<=n;++i)
{
x[i&1]=(x[~i&1]<<a[i])|(x[~i&1]>>a[i]);
for(int j=a[i];j;--j)
x[i&1][a[i]-j]=x[i&1][a[i]-j]|x[~i&1][j];
}
for(int i=0;i<(1<<20);++i)
if(x[n&1][i]) printf("%d\n",i),exit(0);
return 0;
}