int main() {
IOS;
for (cin >> _; _; --_) {
cin >> n >> m;
rep (i, 1, n) cin >> a[i];
sort(a + 1, a + 1 + n);
int x = 1, s = 0; queue<int> q;
for (; x <= n; ++x) {
s += a[x];
if (s == m && q.empty() && x == n) break;
else if (s == m && (q.empty() || q.front() == a[x])) {
int y = x + 1;
while (y <= n && a[y] == a[x]) ++y;
if (y > n) break;
q.push(a[y]);
while (x < y) q.push(a[x++]), s += a[x];
}
else if (s == m && x == n) break;
else if (s == m) {
q.push(a[x]); q.push(a[++x]); q.push(q.front());
q.pop(); s += a[x];
}
else q.push(a[x]);
}
if (s == m) cout << "NO\n";
else {
cout << "YES\n";
while (!q.empty()) cout << q.front() << ‘ ‘, q.pop();
cout << ‘\n‘;
}
}
return 0;
}
int main() {
IOS; set<int> st; n = 1;
while (1) {
st.insert(n * n); ++n;
if (n >= 1e9 / n) break;
}
for (cin >> _; _; --_) {
cin >> n;
if (n & 1) cout << "NO\n";
else if (st.count(n >> 1)) cout << "YES\n";
else if (n >> 1 & 1) cout << "NO\n";
else if (st.count(n >> 2)) cout << "YES\n";
else cout << "NO\n";
}
return 0;
}
贪心
int main() {
IOS;
for (cin >> _; _; --_) {
priority_queue<PII> q;
cin >> n >> m >> k; cout << "YES\n";
rep (i, 1, m) q.push({ 0, i });
rep (i, 1, n) {
cin >> cas;
auto x = q.top(); q.pop();
cout << x.se << ‘ ‘;
x.fi -= cas; q.push(x);
}
cout << ‘\n‘;
}
return 0;
}
int main() {
IOS;
for (cin >> _; _; --_) {
cin >> k >> n >> m; map<int, int> a, b;
int x = n, y = m, d = 0;
rep (i, 1, n) cin >> cas, ++a[cas];
rep (i, 1, m) {
cin >> cas;
if (a[cas]) --a[cas], --x, --y;
else ++b[cas];
}
if (x == y) { cout << x << ‘\n‘; continue; }
if (x < y) swap(a, b), swap(x, y);
for (auto &i : a) d += i.se >> 1;
if (d >= x - y >> 1) cout << y + (x - y >> 1) << ‘\n‘;
else cout << y + (x - y - d * 2) + d << ‘\n‘;
}
return 0;
}
线性dp
首先, 假设开\([l, r]\) 开了 \(r-l+1\) 台电脑, 则必定是从一台电脑, 不断左右边界反复横跳开电脑
即方案数为\(2^{r-l+1}\)
当使用题目给的自动开启方案时, 注意到按区间dp的话
\([l, k], [k + 2, g], [g + 2, r]\) 把\([k + 2, g]\) 归于左边(\([l, k], [k + 2, r]\))或右边(\([l, g], [g + 2, r]\)) 都是可行的
但会多算
故我们在扩展范围的时候除了不使用自动开启方案, 则保证扩展的部分\([k, r]\) 没用使用自动开启
则每次扩展扩展使用一次自动开启\([l, k], [k + 2, r]\), 去重, 变成了线性dp
\(f(i, j)\) 表示前\(i\) 台电脑手动开了 \(j\) 次,
\(f(i, i) = 2^{i - 1}\)
\(f(i + 1 + k, j + k) += f(i, j) * 2^{k - 1} * C_{j + k}^{k}\)
int mod, f[N][N], qp[N];
int fac[N], facinv[N], inv[N];
int C(int n, int m) { return (ll)fac[n] * facinv[m] % mod * facinv[n - m] % mod; }
void init(int n) {
fac[0] = fac[1] = facinv[0] = facinv[1] = inv[0] = inv[1] = qp[0] = 1; qp[1] = 2;
rep (i, 2, n)
qp[i] = (ll)(qp[i - 1] << 1) % mod,
fac[i] = (ll)fac[i - 1] * i % mod,
inv[i] = (ll)(mod - mod / i) * inv[mod % i] % mod,
facinv[i] = (ll)facinv[i - 1] * inv[i] % mod;
}
int main() {
IOS; cin >> n >> mod; init(n);
rep (i, 1, n) f[i][i] = qp[i - 1];
rep (i, 1, n) rep (j, 1, n) rep (k, 1, n - 1 - i)
f[i + k + 1][j + k] = (f[i + k + 1][j + k] + (ll)f[i][j] * qp[k - 1] % mod * C(j + k, k) % mod) % mod;
rep (i, 1, n) m = (m + f[n][i]) % mod; cout << m;
return 0;
}
原文:https://www.cnblogs.com/2aptx4869/p/14727379.html