CSP-S模拟 13

T1 #1695. Soso 的并查集写挂了 \(100pts\)
签。
- 正解:直接并查集维护根链前缀和然后就做完了。\(O(n \log n)\)
点击查看代码
#include <bits/stdc++.h>
#define int long long
const int N = 5e5 + 5;
const int mod = 998244353;
using namespace std;
int n, m, rt, ans;
int U[N], V[N], sum[N];
int a[N], fa[N];
bool vis[N];
vector<int> e[N];
int find(int x)
{
if (fa[x] == x)
return x;
return fa[x] = find(fa[x]);
}
void dfs(int x, int f)
{
vis[x] = 1;
sum[x] = (sum[f] + a[x]) % mod;
for (auto y : e[x])
{
if (y == f)
continue;
dfs(y, x);
}
}
signed main()
{
freopen("sosodsu.in", "r", stdin);
freopen("sosodsu.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= n; i++)
fa[i] = i;
for (int i = 1; i <= m; i++)
{
cin >> U[i] >> V[i];
int x = find(U[i]), y = find(V[i]);
if (x == y)
continue;
e[x].push_back(y);
fa[y] = x;
}
for (int i = 1; i <= n; i++)
{
if (!vis[i])
dfs(find(i), 0);
}
for (int i = 1; i <= n; i++)
fa[i] = i;
for (int i = 1; i <= m; i++)
{
int x = find(U[i]), y = find(V[i]);
ans = (ans + sum[U[i]] - sum[x] + a[x]) % mod;
ans = (ans + sum[V[i]] - sum[y] + a[y]) % mod;
fa[y] = x;
}
cout << ans % mod;
}
T2 #1696. 迁跃 \(40pts\)
签到DP,赛时没大样例细节锅了。
- 正解:简单树形 DP
点击查看代码
#include <bits/stdc++.h>
#define int long long
const int N = 1e5 + 5;
using namespace std;
int n, k;
int f[N][2];
vector<pair<int, int>> e[N];
void dfs(int x, int fa)
{
int cnt = 0, tmp = 0;
for (auto y : e[x])
{
int to = y.first, w = y.second;
if (fa == to)
continue;
dfs(to, x);
cnt++;
tmp = max(tmp, max(f[to][1], f[to][0]) - max(0ll, f[to][1] - k + w) + w);
f[x][1] += max({0ll, f[to][1] - k + w});
}
f[x][0] = f[x][1] + tmp;
// cerr << x << ' ' << f[x][0] << ' ' << f[x][1] << '\n';
}
signed main()
{
freopen("clock.in", "r", stdin);
freopen("clock.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> k;
for (int i = 1; i <= n - 1; i++)
{
int u, v, w;
cin >> u >> v >> w;
e[u].push_back({v, w});
e[v].push_back({u, w});
}
dfs(1, 0);
cout << f[1][0];
}
T3 #1697. 回文回文回 IV \(100pts\)
抽象计数。
- 正解:注意到只有相加等于 0 的数对有贡献,找到所有数对与孤立点,特判无解与 0 的贡献即可,大部分数据都可以预处理,可以达到 \(O(n)\) 。
点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int mod = 998244353;
const int N = 1e5 + 5;
const int inf = 1e6;
int n, T, ans = 1;
int a[N], jc[N];
int qpow(int x, int y)
{
int mi = x, ans = 1;
while (y > 0)
{
if (y & 1)
ans = ans * mi % mod;
mi = mi * mi % mod;
y >>= 1;
}
return ans;
}
void solve()
{
int g = inf, gtot = 0, num = 0, g0 = 0;
ans = 1;
map<int, int> t, tt;
map<int, bool> vis;
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i], t[a[i]]++;
tt = t;
for (int i = 1; i <= n; i++)
{
if (t[a[i]] == 0)
continue;
if (a[i] == 0)
{
if (t[0] == 1)
{
num++;
g0 = 1;
g = 0, t[0]--;
}
else
t[0] -= 2;
continue;
}
if (t[-a[i]])
t[a[i]]--, t[-a[i]]--;
else
{
num++;
g = a[i], t[a[i]]--;
}
}
if ((num > 1 && n % 2 == 1) || (n % 2 == 0 && num - g0 > 1))
{
cout << 0 << '\n';
return;
}
ans = ans * jc[(n - 1) / 2] % mod * qpow(jc[tt[0] / 2], mod - 2) % mod;
ans = ans * qpow(2, (n - 1) / 2 - tt[0] / 2) % mod;
tt[g]--;
int t0 = tt[0];
tt[0] /= 2;
// cerr << ans << '\n';
for (int i = 1; i <= n; i++)
{
if (a[i] == g)
gtot++;
if (vis[a[i]])
continue;
if (tt[a[i]] == 0 || a[i] == 0)
continue;
vis[a[i]] = 1;
vis[-a[i]] = 1;
// cout << i << ' ' << tt[a[i]] << '\n';
ans = ans * jc[tt[a[i]]] % mod;
}
// cerr << gtot;
// cerr << ans << '\n';
ans = ans * gtot % mod;
if (t0)
ans = ans * jc[t0] % mod;
cout << ans % mod << '\n';
}
signed main()
{
freopen("paliniv.in", "r", stdin);
freopen("paliniv.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> T;
jc[0] = 1;
for (int i = 1; i <= N - 5; i++)
jc[i] = (jc[i - 1] * i) % mod;
while (T--)
solve();
}
T4 #1698. 紫藤萝瀑布 \(0pts\)
简单启发式合并,赛时没时间做了。
- 正解:直接使用 map 和并查集暴力统计,启发式合并。一个显然的性质是把一个集合改为同色的最小次数是集合大小减去众数 ,超大常数的 \(O(n \log n)\) ,数据 1e6 不卡常过的比较极限。
点击查看代码
#include <bits/extc++.h>
const int N = 1e6 + 5;
using namespace std;
using namespace __gnu_pbds;
int n, m;
gp_hash_table<int, int> mp[N];
int a[N], fa[N], cnt;
int maxn[N], ans;
int find(int x)
{
if (fa[x] == x)
return x;
return fa[x] = find(fa[x]);
}
void mer(int x, int y)
{
fa[x] = y;
ans += maxn[x] + maxn[y];
for (auto nw : mp[x])
{
mp[y][nw.first] += nw.second;
maxn[y] = max(maxn[y], mp[y][nw.first]);
}
mp[x].clear();
ans -= maxn[y];
}
void merge(int x, int y)
{
int fx = find(x), fy = find(y);
if (fx == fy)
return;
if (mp[fx].size() > mp[fy].size())
mer(fy, fx);
else
mer(fx, fy);
}
signed main()
{
freopen("flower.in", "r", stdin);
freopen("flower.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
fa[i] = i;
maxn[i] = 1;
mp[i][a[i]]++;
}
while (m--)
{
char op;
int x, y;
cin >> op;
if (op == '=')
{
cin >> x >> y;
merge(x, y);
}
else
cout << ans << '\n';
}
}
总结
- 赛后 T4 30min 过了。
- 纯纯信心赛但是打爆了,如果不是 T3 结论假了 2h+ 或许能AK。
- 比赛时心态小炸,以后不能弘文了。
- (´・ω・`)

浙公网安备 33010602011771号