小蛐蛐 NOIP Round 1 总结
分数:\(100 + 15 + 0 + 0 = 115\)
为什么这“NOIP 模拟赛”里三道题都用到了 9 级知识点。真是无敌了。
不过由于不少同学的摆烂态度,我竟然意外捞到了 ZYZ rank 1,总 rank 2,有点意思。
T1
我用了一个和题解略有不同的思路。
题面描述很玄乎,实际上就是从原树中选出来一个连通块。
设 \(f(i, 0/1)\) 表示目前考虑到节点 \(i\),且 \(i\) 是/否作为连通块的根时,所能获得的最大分数。初始时 \(f(i, 1) = score(0), f(i, 0) = score(1)\),因为当一个节点不是根时,它上方永远有一条边与之相连,也就是说度数至少为 \(1\)。
我们从下往上进行转移,就像一般的树形 DP 一样。对于每一个非叶节点 \(u\),我们对其子节点 \(v\) 按照 \(f(v, 0)\) 进行排序,并计算其前缀和 \(sum\)。如果我们选择 \(i\) 个节点,那么当 \(u\) 作为根时,其度数为 \(i\);当 \(u\) 不作为根时,其度数为 \(i + 1\),因为其上面还有一条边。因此,我们可以得到状态转移方程:
\[f(u, 0) = \max(f(u, 0), \max_{i=1}(score(i + 1) + sum(i)))
\\
f(u, 1) = \max(f(u, 1), \max_{i=1}(score(i) + sum(i)))
\]
最后我们统计答案时,取 \(\max_{u=1}^{n}(f(u, 1))\) 即可。
#include <bits/stdc++.h>
#define int long long
const int N = 2e5+10;
std::vector<int> g[N];
int n, score[N], dp[N][2];
void dfs(int u, int pre) {
dp[u][0] = score[1]; dp[u][1] = score[0];
std::vector<int> chiDP;
for (auto &v : g[u]) {
if (v == pre) continue;
dfs(v, u);
chiDP.push_back(dp[v][0]);
}
std::sort(chiDP.begin(), chiDP.end(), [](int a, int b) {
return a > b;
});
for (int i = 1; i < chiDP.size(); i++) {
chiDP[i] += chiDP[i-1];
}
for (int i = 0; i < chiDP.size(); i++) {
dp[u][0] = std::max(dp[u][0], score[i+2] + chiDP[i]);
dp[u][1] = std::max(dp[u][1], score[i+1] + chiDP[i]);
}
}
signed main() {
freopen("tree.in", "r", stdin);
freopen("tree.out", "w", stdout);
std::ios::sync_with_stdio(false); std::cin.tie(0);
std::cin >> n;
for (int i = 0; i <= n - 1; i++) {
std::cin >> score[i];
}
score[n] = score[n-1];
for (int i = 1; i <= n - 1; i++) {
int u, v;
std::cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1, 0);
int ans = -1e18;
for (int i = 1; i <= n; i++) {
ans = std::max(ans, dp[i][1]);
}
std::cout << ans << '\n';
return 0;
}
T3
感觉我再怎么说也没有 XQQ 自己说的好,直接搬过来吧。(我怎么这么懒。)

#include <bits/stdc++.h>
#define int long long
const int N = 1e6+10, MOD = 1e9+7;
int T;
int border[N], nxt0[N], nxt1[N], f[N], sumF[N];
inline std::string decode(std::string s, int len) {
std::string res;
for (auto const &ch : s) {
int num;
if (ch >= 'a' && ch <= 'z') num = ch - 'a';
else num = ch - 'A' + 26;
for (int i = 4; i >= 0; i--) {
if (num & (1 << i)) res.push_back(1);
else res.push_back(0);
}
}
if (res.size() > len) return res.substr(0, len);
else return res;
}
signed main() {
freopen("coin.in", "r", stdin);
freopen("coin.out", "w", stdout);
std::ios::sync_with_stdio(false); std::cin.tie(0);
std::cin >> T;
while (T--) {
memset(border, 0, sizeof border);
memset(nxt0, 0, sizeof nxt0);
memset(nxt1, 0, sizeof nxt1);
memset(f, 0, sizeof f);
memset(sumF, 0, sizeof sumF);
int n, m;
std::string s1_, s2_;
std::cin >> n >> s1_ >> m >> s2_;
std::string s1 = decode(s1_, n), s2 = decode(s2_, m);
if (n == 0) {std::cout << "0\n"; continue;}
border[0] = 0;
for (int i = 1; i < n; i++) {
int j = border[i-1];
while (j > 0 && s1[i] != s1[j]) j = border[j-1];
if (s1[i] == s1[j]) j++;
border[i] = j;
}
nxt0[0] = (s1[0] == 0), nxt1[0] = (s1[0] == 1);
for (int i = 1; i < n; i++) {
nxt0[i] = (s1[i] == 0) ? i + 1 : nxt0[border[i - 1]];
nxt1[i] = (s1[i] == 1) ? i + 1 : nxt1[border[i - 1]];
}
int curr = 0; bool done = false;
for (auto const &ch : s2) {
if (ch == 0) curr = nxt0[curr];
else curr = nxt1[curr];
if (curr == n) {done = true; break;}
}
if (done) {std::cout << "0\n"; continue;}
for (int i = 0; i < n; i++) {
int j;
if (s1[i] == 0) j = nxt1[i];
else j = nxt0[i];
int s = 0;
if (i > 0) s = sumF[i-1];
if (j > 0) s = (s - sumF[j-1] + MOD) % MOD;
f[i] = (2 + s) % MOD;
if (i == 0) sumF[i] = f[i];
else sumF[i] = (sumF[i-1] + f[i]) % MOD;
}
if (curr == 0) std::cout << sumF[n-1] << '\n';
else std::cout << (sumF[n-1] - sumF[curr-1] + MOD) % MOD << '\n';
}
return 0;
}

浙公网安备 33010602011771号