牛客练习赛128
A Cidoai 的幂次序列
给定
(注:右上角为
你需要保证对于所有
直接两个数即可。
cout << "2\n";
cout << n - 1 << " " << 1 << '\n';
B Cidoai 的平均数对
给定
背包变种问题,真搞不懂为什么写不出来
这个题的难点在于转换问题,只需要对于每个
- 操作之后需要满足平均值不超过 0,可以设置一个偏移量,使之 DP 时不超过这个值即可。
- 也可以先将所有
的数全部先选择了 (这些数是必选的),然后将这些数的和作为容量来做 DP
没有想到转换的方式... 这是第二种,也感觉更好理解。
int f[510 * 510];
void solve() {
int n, k;cin >> n >> k;
vector<int> a(n + 1), b(n + 1);
for (int i = 1;i <= n;i++)cin >> a[i] >> b[i], b[i] -= k;
int sum = 0, ans = 0;
for (int i = 1;i <= n;i++) {
if (b[i] <= 0)ans += a[i], sum += b[i];
}
sum = -sum;
for (int i = 1;i <= n;i++) {
if (b[i] <= 0)continue;
for (int j = sum;j >= b[i];j--) {
f[j] = max(f[j], f[j - b[i]] + a[i]);
}
}
cout << f[sum] + ans << '\n';
}
C Cidoai 的树上方案
给定大小为
若不选择位置,则其儿子可以选择也可以不选择
若选择当前位置,则其儿子一定是不选择的
#define int long long
constexpr int mod = 998244353;
void solve() {
int n;cin >> n;
vector<int> p(n + 1);
for (int i = 2;i <= n;i++)cin >> p[i];
vector<array<int, 2>> f(n + 1, {1,1});
for (int i = n;i >= 1;i--) {
f[p[i]][0] *= (f[i][0] + f[i][1]) % mod;f[p[i]][0] %= mod;
f[p[i]][1] *= f[i][0];f[p[i]][1] %= mod;
}
cout << (f[1][0] + f[1][1])%mod << '\n';
}
等价于
#define int long long
constexpr int mod = 998244353;
void solve() {
int n;cin >> n;
vector<vector<int>> g(n + 1);
for (int i = 2;i <= n;i++) {
int x;cin >> x;
g[x].push_back(i);
g[i].push_back(x);
}
vector<array<int, 2>> f(n + 1, {1,1});
auto dfs = [&](auto self, int u, int fa = -1) ->void {
for (auto v : g[u]) {
if (v == fa)continue;
self(self, v, u);
f[u][0] *= f[v][0] + f[v][1];f[u][0] %= mod;
f[u][1] *= f[v][0];f[u][1] %= mod;
}
};
dfs(dfs, 1);
cout << (f[1][0] + f[1][1]) % mod << '\n';
}
D Cidoai 的字符集合
Cidoai 听到了
他认为这些歌中有一些是相似的。他定义两首歌
你需要为他求出这
由题意可以知道,当两个歌曲有一个单词相同就可以划分到同一个集合,(即两个歌曲满足要求就可以连一个边),关键如何快速添加边
注:多个连通块也满足要求,只要这个连通块的大小大于等于 2 就可以合并成为一个连通块
所以最后只存在两种:若干个大小为 1 的连通块与一大个连通块,即连通块大小为 1 的个数+1
并查集
void solve() {
int n;cin >> n;
map<string, int>mp;
DSU dsu(n + 1);
for (int i = 1;i <= n;i++) {
int k;cin >> k;
while (k--) {
string s;cin >> s;
if (mp.count(s)) {
dsu.merge(i, mp[s]);
} else {
mp[s] = i;
}
}
}
int ans = 1;
for (int i = 1;i <= n;i++) {
if (dsu.size(i) == 1)ans++;
}
cout << ans << '\n';
}