. 小红的
直接枚举就好
神奇的代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
const int mod = 998244353;
void solve()
{
std::string s; std::cin >> s;
for (char c : s)
{
if (c != 'r' && c != 'e' && c != 'd')
{
std::cout << "No" << endl;
return;
}
}
std::cout << "Yes" << endl;
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr); std::cout.tie(nullptr);
int _t = 1;
// std::cin >> _t;
while (_t--) solve();
return 0;
}
.小红的矩阵构造
构造
我们就让前2个不同就好了,可以发现只有1行或者1列的情况可以,其他就不行了,也要注意
的情况,特判一下就好了
神奇的代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
const int mod = 998244353;
void solve()
{
int n = 0, m = 0; std::cin >> n >> m;
if ((n != 1 && m != 1) || (n * m == 1))
{
std::cout << -1 << endl; return;
}
if (n == 1)
{
std::cout << "10";
for (int i = 1; i <= m - 2; i++) std::cout << "0";
}
else
{
std::cout << "1" << endl;
std::cout << "0" << endl;
for (int i = 1; i <= n - 2; i++) std::cout << "0" << endl;
}
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr); std::cout.tie(nullptr);
int _t = 1;
// std::cin >> _t;
while (_t--) solve();
return 0;
}
.小红的数据结构
模拟
直接分别用一个和一个
去模拟整个过程,并记录弹出的数,一共就这四种情况
- 都能和
数组匹配上就是
- 都匹配不上就是
能匹配上就是
能匹配上就是
神奇的代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
const int mod = 998244353;
void solve()
{
int n = 0, q = 0; std::cin >> n >> q;
std::stack<int> stk;
std::queue<int> que;
std::vector<int> a(n, 0), stk_vec, que_vec;
for (int i = 0; i < n; i++) std::cin >> a[i];
for (int i = 1; i <= q; i++)
{
int op; std::cin >> op;
if (op == 1)
{
int v; std::cin >> v;
stk.push(v); que.push(v);
}
else
{
int top_stk = stk.top();
int que_stk = que.front();
stk.pop(); que.pop();
stk_vec.push_back(top_stk);
que_vec.push_back(que_stk);
}
}
bool stk_ok = true, que_ok = true;
for (int i = 0; i < n; i++) if (stk_vec[i] != a[i]) {stk_ok = false; break;}
for (int i = 0; i < n; i++) if (que_vec[i] != a[i]) {que_ok = false; break;}
if (stk_ok == false && que_ok == false) {std::cout << -1 << endl; return;}
if (stk_ok == true && que_ok == true) {std::cout << "both" << endl; return;}
if (stk_ok == true) {std::cout << "stack" << endl; return;}
if (que_ok == true) {std::cout << "queue" << endl; return;}
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr); std::cout.tie(nullptr);
int _t = 1;
// std::cin >> _t;
while (_t--) solve();
return 0;
}
小红的部分字符串
并查集 快速幂
-
限制条件中相同的字符可以看作一个连通块,这部分可以通过并查集实现
-
接下来就是组合数学中的染色问题,每个连通块都有
种选择
神奇的代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
const int mod = 998244353;
int qpower(int y, int x)
{
int r = 1;
while(x)
{
if (x & 1) r = r * y % mod;
y = y * y % mod;
x >>= 1;
}
return r;
}
int faz[200010];
int find(int x)
{
if (faz[x] == x) return x;
return faz[x] = find(faz[x]);
}
void Merge(int x, int y)
{
int prex = find(x), prey = find(y);
faz[prey] = prex;
}
void solve()
{
int n = 0, k = 0;
std::cin >> n >> k;
for (int i = 1; i <= n; i++) faz[i] = i;
for (int i = 1; i <= k; i++)
{
int su, sv; std::cin >> su >> sv;
Merge(su, sv);
}
int cnt = 0;
for (int i = 1; i <= n; i++)
{
if (faz[i] == i) cnt++;
}
std::cout << qpower(26, cnt) % mod;
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr); std::cout.tie(nullptr);
int _t = 1;
// std::cin >> _t;
while (_t--) solve();
return 0;
}
. 小红的树权值
树的最小点覆盖 树形
剩余的所有联通块大小都为
删完以后,图里不能再有任何边。因为只要还有一条边连着两个点,那这两个点就在同一个连通块里,这个连通块大小至少是
,不符合要求。
所以“所有连通块大小都为 等价于:
- 剩下的每个点都是孤立点
- 任意两个剩余点之间都没有边
这个本质上就是 树上的最小点覆盖:选最少的点,使得每条边都被覆盖
那么就变成了一个树形的板子题
:在
的子树中,保留
时,使这棵子树满足要求的最小删除数
:在
的子树中,删除
时,使这棵子树满足要求的最小删除数
最后:就是
这棵子树的权值。
设 的儿子是
。
如果
保留:dp[u][0]
因为 没删,那么边
不能留下。
所以对于每个儿子 ,必须删掉
。
因此:
如果
删除:dp[u][1]
那边 自然消失了。
这时候每个儿子 就自由了:
- 可以删
- 也可以不删
只要它自己的子树内部合法就行。
所以每个儿子取最优:
前面的 1 是因为删掉了 (u) 本人。
叶子节点会怎样?
如果 是叶子:
- 保留它:不用删任何点,
- 删除它:删 1 个点,
所以:
神奇的代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
const int mod = 998244353;
std::vector<int> g[100010];
void solve()
{
int n = 0; std::cin >> n;
for (int i = 1; i <= n; i++) g[i].clear();
std::vector<std::array<int, 2>> dp(n + 1, {0, 0});
for (int i = 1; i < n; i++)
{
int u, v;
std::cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
// dp[u][0] 保留u
// dp[u][1] 删掉u
auto dfs = [&](auto&& dfs, int s, int fa) -> void
{
dp[s][0] = 0;
dp[s][1] = 1;
for (int v : g[s])
{
if (v == fa) continue;
dfs(dfs, v, s);
dp[s][0] += dp[v][1];
dp[s][1] += std::min(dp[v][0], dp[v][1]);
}
};
dfs(dfs, 1, 0);
for (int i = 1; i <= n; i++)
{
std::cout << std::min(dp[i][0], dp[i][1]) << endl;
}
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr); std::cout.tie(nullptr);
int _t = 1;
std::cin >> _t;
while (_t--) solve();
return 0;
}
.小红的部分不同字符串
把位置看成点,把限制 s_i != s_{a_i} 看成一条边,那么题目就变成了:
- 用
26种颜色给图染色 - 要求每条边两端颜色不同
- 求合法染色方案数
这张图的特殊之处在于:每个点恰好连向一个点 a_i,所以它是一个 函数图。
函数图的每个连通块一定是:
一个环 + 若干棵挂在环上的树
所以整题只需要拆成两部分考虑:
- 环外的树怎么贡献
- 环本身怎么贡献
环外的树很好算。
设某个点 u 不在环上,它只需要满足:
如果 a_u 的颜色已经确定,那么 u 就有 25 种可选颜色。
所以:每个非环点都会给答案贡献一个 25
如果总共有 cnt 个非环点,那么它们总贡献就是:
真正麻烦的是环。
设一个环长为 c,有 q 种颜色时,环的合法染色数是经典公式:
这题里 q = 26,所以长度为 c 的环贡献为:
即:
c为奇数:25^c - 25c为偶数:25^c + 25
所以整题答案就是:
- 先乘上所有非环点的贡献
25^{cnt} - 再对每个环乘上对应的环染色贡献
也就是:
剩下的问题只有一个:怎么找环?
做法是 拓扑剥叶子:
- 统计每个点的入度
- 把所有入度为
0的点入队 - 不断删除这些点,并让它指向的点入度减一
- 新出现入度为
0的点继续入队
这样做的原因是:
- 入度为
0的点一定不在环上 - 不断剥掉这些点后,最后剩下的点一定都在环上
于是:
- 被剥掉的点 = 非环点
- 没被剥掉的点 = 所有环上的点
再顺着 a[i] 跑一圈,就能求出每个环的长度。
神奇的代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
const int mod = 998244353;
int qpower(int y, int x)
{
int r = 1;
while(x)
{
if (x & 1) r = r * y % mod;
y = y * y % mod;
x >>= 1;
}
return r;
}
void solve()
{
int n = 0; std::cin >> n;
std::vector<int> a(n + 1, 0), in(n + 1, 0), del(n + 1, 0), vis(n + 1, 0);
for (int i = 1; i <= n; i++)
{
std::cin >> a[i];
in[a[i]]++;
}
std::queue<int> q;
for (int i = 1; i <= n; i++)
{
// 入度为0, 说明在链首,这里可能不止有一个连通块
if (in[i] == 0) q.push(i);
}
int cnt = 0; // 非环点个数
while (!q.empty()) // 把链上的点摘干净
{
int u = q.front();
q.pop();
del[u] = 1;
cnt++;
int v = a[u];
in[v]--;
if (in[v] == 0) q.push(v);
}
int ans = qpower(25, cnt);
// 开始处理环上的点
for (int i = 1; i <= n; i++)
{
if (del[i] || vis[i]) continue;
int len = 0;
int u = i;
while(!vis[u])
{
vis[u] = 1;
len++;
u = a[u];
}
int now = qpower(25, len);
if (len & 1) now = (now - 25 + mod) % mod;
else now = (now + 25) % mod;
ans = ans * now % mod;
}
std::cout << ans % mod << endl;
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr); std::cout.tie(nullptr);
int _t = 1;
// std::cin >> _t;
while (_t--) solve();
return 0;
}

京公网安备 11010502036488号