题解:CF2028F Alice's Adventures in Addition
思路
显然 dp.
我们设
可以考虑将乘起来的划分为一个段,那么对于每一个
那么易得 dp 的转移方程为
显然是会超时的,考虑优化。
我们注意到
若
此处可以用前缀或优化掉。
若
因为
可是这样,会造成一个问题,如果
因为如果我们将
如果我们每次都遍历一遍那些
即可,每次初始化
综上所述
在转移
易发现这个过程可以用 biset 优化,此时时间复杂度为
::::success[Code]
#include <bits/stdc++.h>
using namespace std;
#define inl inline
#define ls (p << 1)
#define rs (p << 1 | 1)
#define Cst constexpr
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
#define pb(x) push_back(x)
#define SZ(x) (int)(x).size()
#define ppc(x) __builtin_popcount(x)
#define All(x) (x).begin(), (x).end()
#define mems(x, v) memset((x), (v), sizeof(x))
#define memc(x, y) memcpy((x), (y), sizeof(x))
Cst int lgM = 14, M = 1e4 + 5;
auto fIO = []() {
return cin.tie(0)->sync_with_stdio(0), 0;
}();
int n, m;
bitset<M> dp, pre, z;
deque<pair<int, bitset<M>>> q;
signed main() {
int T; cin >> T;
while (T--) {
cin >> n >> m;
deque<pair<int, bitset<M>>>().swap(q);
dp.reset(), pre.reset(), z.reset();
dp[0] = pre[0] = 1;
for (int i = 1; i <= n; ++i) {
int a; bitset<M> nxt = z; cin >> a;
if (a == 0) { nxt |= pre; z = nxt, q.push_front({0, dp}); }
else if(a == 1) nxt |= (dp | (dp << 1));
else {
long long mul = 1; q.push_front({a, dp});
for (auto [f, s] : q) {
if (mul == 0 || mul * f > m) break;
mul *= f;
nxt |= s << mul;
}
}
pre |= nxt; dp = nxt;
if (q.size() > lgM) q.pop_back();
}
cout << (dp[m] ? "YES" : "NO") << '\n';
}
return ~~(0 ^ 0);
}
::::