rt. 我赛时注意到正负数的差只能在 [−2000,2000] 之间,因此可以跑 O(nV) 的背包,然而没调出来。。。这应该是比 std 的 O(n2V/w) 更优的,求助大佬是哪里的问题。
对拍的结果是如果 n 很大,直接爆 int 了。
#include <bits/stdc++.h>
using namespace std;
using LL = __int128;
using ll = long long;
using ldb = long double;
using vi = vector < int >;
using ull = unsigned long long;
#define pb push_back
#define ve vector < edge >
#define lowbit(x) ((x) & -(x))
#define me(a, b) memset(a, b, sizeof(a))
#define L(i, j, k) for (int i = j; i <= int(k); i++)
#define R(i, j, k) for (int i = j; i >= int(k); i--)
#define debug cerr << __FILE__ << ": " << __LINE__ << '\n';
#define qio() ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
namespace io {
char buf[1 << 21], *p1 = buf, *p2 = buf;
#define gc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
int read() {
int res(0), f(1);
char ch(getchar());
while (ch < '0' || ch > '9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
res = res * 10 + (ch ^ '0');
ch = getchar();
}
return res * f;
}
ll readl() {
ll res(0);
int f(1);
char ch(getchar());
while (ch < '0' || ch > '9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
res = res * 10 + (ch ^ '0');
ch = getchar();
}
return res * f;
}
}
using io::read;
using io::readl;
template < class T >
ostream& operator << (ostream& out, vector < T > v) {
out << '[';
if (!v.empty()) {
L(i, 0, v.size() - 2)
out << v[i] << ',';
out << v[v.size() - 1];
}
return out << ']';
}
namespace Dbg {
template < class T >
void dbg(char *f, T t) {
cerr << f << '=' << t << endl;
}
template < class T, class ...Ar >
void dbg(char *f, T x, Ar... y) {
while (*f != ',')
cerr << *f++;
cerr << '=' << x << ',';
dbg(f + 1, y...);
}
}
#define gdb(...) cerr << "gdb in line " <<__LINE__ << ": ", Dbg::dbg((char*)#__VA_ARGS__,__VA_ARGS__);
const int N = 2e3 + 5; // Adjust
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3fll;
int _[N << 1], __[N][N << 1];
int n, *f = &_[N], *g[N];
vi nb, neg, pos;
int main() {
n = read();
for (int i = 1, x; i <= n; i++) {
if ((x = read()) > 0)
pos.pb(x);
else if (x < 0)
neg.pb(x);
if (x != 0)
nb.pb(x);
g[i - 1] = &__[i - 1][N];
}
n = nb.size();
if (pos.empty()) {
int ans = -inf;
for (int num : neg)
ans = max(ans, num);
return printf("%d\n", ans), 0;
}
if (neg.empty()) {
int ans = 0;
for (int num : pos)
ans = max(ans, num);
return printf("%d\n", ans), 0;
}
// f[0] = 1;
for (int num : nb) {
f[num]++;
if (num < 0)
for (int dlt = max(-2000, -2000 + num); dlt <= min(2000, 2000 + num); dlt++)
f[dlt] += f[dlt - num] - (dlt == 2 * num), assert(dlt - num >= -2000);
else
for (int dlt = min(2000, 2000 + num); dlt >= max(-2000, -2000 + num); dlt--)
f[dlt] += f[dlt - num] - (dlt == 2 * num), assert(dlt - num <= 2000);
// for (int dlt = -31; dlt <= 31; dlt++)
// gdb(num, dlt, f[dlt]);
// cout << "__________\n";
}
// f[0]--;
// gdb(f[0]);
int ans = -inf;
for (int i = 0; i < n; i++) {
int num = nb[i];
for (int dlt = -2000; dlt < max(-2000, -2000 + num); dlt++)
g[i][dlt] = f[dlt];
for (int dlt = min(2000, 2000 + num) + 1; dlt <= 2000; dlt++)
g[i][dlt] = f[dlt];
if (nb[i] > 0)
for (int dlt = max(-2000, -2000 + nb[i]); dlt <= min(2000, 2000 + num); dlt++)
g[i][dlt] = f[dlt] - g[i][dlt - nb[i]];
else
for (int dlt = min(2000, 2000 + num); dlt >= max(-2000, -2000 + num); dlt--)
g[i][dlt] = f[dlt] - g[i][dlt - nb[i]];
// if (!i)
// gdb(g[i][0], f[0]);
// if (num == 31)
// gdb(f[0], g[i][0], g[i][-31], f[-31]);
if (num > 0) {
for (int dlt = -2000; dlt <= 0; dlt++)
if (g[i][dlt]) {
ans = max(ans, dlt + num);
// if (dlt + num == 30)
// gdb(dlt, g[i][dlt], num);
}
} else {
for (int dlt = 0; dlt <= 2000; dlt++)
if (g[i][dlt])
ans = max(ans, g[i][dlt] + num);
}
// gdb(i, ans);
}
return printf("%d\n", ans), 0;
}