abc209
C - Not Equal 285
求长度为 n,两两不同,且满足 的数组的数量
数组 c 排序,答案就是 ,其中 个位置被前面占了
D - Collision 686
给定一棵树,q 次询问,一个人从 u 走向 v,另一个人从 v 走向 u,同时同速。问两人在点上还是在边上相遇
若 u 和 v 深度奇偶性相同则在点上相遇,否则在边上
E - Shiritori 2153
两个人成语接龙,每个人说的单词前三个字母须与上一个人说的最后三个字母同。给定单词表,单词可重复使用,不能说者输,问从每个单词出发谁会赢(或者平局)
把每个单词视为边,把边(单词)的状态放在它的终端点(三个字母)上,按拓扑排序的逆序递推状态,最后没有状态的点是平局
(似乎我对输赢的定义跟大家相反)
先手必败点:存在先手必胜后继点
先手必胜点:所有后继点必败
注意:跟正常拓扑排序不同,不是度为0才入队,而是状态确定就入队,度只是为状态的推断服务的。否则,若 u 的后继既有必胜点又有个环,可能导致 u 的状态没法更新,但实际上 u 是必败点
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
int n;
cin >> n;
vector<string> edges;
map<string, vector<string>> g;
map<string, int> deg;
while (n--) {
string s;
cin >> s;
string u = s.substr(0, 3), v = s.substr(s.size() - 3); // u -> v
edges.push_back(v);
g[v].push_back(u); // 反图
deg[u]++;
if (!deg.count(v)) deg[v] = 0; // 别漏了
}
queue<string> q;
map<string, int> f;
for (auto [s, d] : deg) {
if (!d) q.push(s), f[s] = 1; // 先手胜
}
while (q.size()) {
auto v = q.front(); q.pop();
for (auto u : g[v]) {
deg[u]--;
if (f[v] == 1 && f[u] != 2) f[u] = 2, q.push(u); //首次确定u为必败态
else if (!deg[u] && f[u] != 2) f[u] = 1, q.push(u); //拆完出边仍未必败的才是必胜态
}
}
string ans[] = {"Draw", "Takahashi", "Aoki"};
for (auto s : edges) {
cout << ans[f[s]] << '\n';
}
return 0;
}
F - Deforestation 2307
把 n 棵树砍完,每次选择一棵树 ,花费 然后使 变成 。问有多少种砍树顺序的花费并列最小
对于相邻两项 ,应该先砍较高的。不相邻的两棵树实际上不会相互影响
表示砍前 棵树,第 棵树是第 个被砍的。注意 不是最终顺序
若 ,则 ,注意这里实际上是通过把第 个被砍的树后移以腾出 号位置,然后把 放在 处来得到新的砍树顺序的
若 ,则 ,注意根据上述构造方法, 也要算入
若 ,那么可以把 插入前 棵树的任何砍树顺序的任何位置
记录一下前缀和,。题解把这类 dp 叫 “insertion DP”
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll P = 1e9 + 7;
const int N = 4e3 + 5;
ll n, a[N], f[N][N], s[N];
int main() {
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
f[1][1] = s[1] = 1;
for (int i = 2; i <= n; i++) {
for (int j = 1; j <= i; j++) {
if (a[i] < a[i - 1]) f[i][j] = s[j - 1];
if (a[i] > a[i - 1]) f[i][j] = (s[i - 1] - s[j - 1]) % P;
if (a[i] == a[i - 1]) f[i][j] = s[i - 1];
}
for (int j = 1; j <= i; j++)
s[j] = (s[j - 1] + f[i][j]) % P;
}
ll ans = accumulate(f[n] + 1, f[n] + 1 + n, 0ll) % P;
cout << (ans + P) % P;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通