【CF比赛记录】Codeforces Round 1007 (Div. 2)
Codeforces Round 1007 (Div. 2) 比赛记录
比赛链接
很喜欢的一场比赛,题目质量很高,不是手速场,做出题超级有成就感,赛时切掉了 A - D1,上大分了。
B卡得有点久,其实是一个很常用的构造手法但一开始没想到。
过题记录:
A. The Play Never Ends
题意大概就是,每场两个人打,一个人观战。如果有一个人以及连续打了两场,则这场无论如何这个人都要下去,否则输的那个下去,问第
假设第一场打的人分别是 A 和 B,A 获胜,观战者是 C,手玩一下小一点的样例发现,第二场 C 一定上场,此时 A 已经打了一场,那么 A 和 C 打完后,无论如何,下的都是 A,再打一场后,由于 C 已经打了两场了,所以无论如何,下的都是 C,如此进行下去可以发现,输赢无所谓,因为总有一方连续打了两场,必须下,因此实际上就是三个人轮换,所以 C 观战的时候就是
void solve()
{
int n;cin >> n;
if(n % 3 == 1)cout << "YES\n";
else cout << "NO\n";
}
B. Perfecto
我愿称之为本场前四题最难题,因为我好友列表都被卡了。
一开始我天真地以为只有
因此首先判断
然后再看如何构造,这里用到了一个构造题很常用的手法,就是先把一般的搞出来,再去修。
我们先初始化答案排列为
然后依次遍历,并且记录前缀和,一旦当前
然后再来证一个事情,就是交换的时候
假设当前为第
const int N = 5e5 + 9;
map<int, bool> vis;
int a[N];
void solve()
{
int pre = 0;
int n;cin >> n;
if(vis.count((n + 1) * n / 2)) {
cout << -1 << '\n';
return;
}
for(int i = 1;i <= n;i ++) {
a[i] = i;
}
for(int i = 1;i <= n;i ++) {
if(vis.count(pre + a[i])) {
swap(a[i], a[i + 1]);
}
pre += a[i];
}
for(int i = 1;i <= n;i ++) {
cout << a[i] << " \n"[i == n];
}
}
void init() {
for(int i = 1;i < N;i ++) {
vis[i * i] = true;
}
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
init();
int t = 1;cin >> t;
while(t --)solve();
return 0;
}
C. Trapmigiano Reggiano
本场最有趣最好玩的题出现了!
题意大概就是,一只老鼠,在树上一个起点,要去树上一个终点,现在要你构造出一个长度为
手玩了好多样例后发现一定有解,以下是我的见解:
我们以起点作为根,对于每一个结点,它至多有一个子结点的子树是包含终点的,因此我们要让老鼠先把非终点的子树走完。对于非终点的子树,我们从下往上选,一定是可以回到当前结点的,因为我们选的数是从下往上走的,我们的老鼠是从上往下走的,那么二者一定会相遇,而后就一起往上走回去。把非终点的子树选完后,再选择当前这个结点,把老鼠引回来,而后往终点子树走,继续按照上述流程递归下去,最后一定会到达终点。
因此我的代码思路就是:先以起点为根 DFS 一次,标记一下每一棵子树是否有终点,然后再来一次 DFS,按照上述流程加点形成答案序列。
赛后看了群里面大佬的解析并细细品味了一下我的代码,这不就是拓扑排序嘛,我们每次选择度为
const int N = 1e5 + 9;
vector<int> g[N];
bool dp[N];
int n, st, ed;
vector<int> ans;
void dfs(int now, int pre) {
dp[now] = (now == ed);
for(auto &i : g[now]) {
if(i == pre) {
continue;
}
dfs(i, now);
dp[now] = (dp[now] || dp[i]);
}
sort(g[now].begin(), g[now].end(), [] (const int &u, const int &v) {
return dp[u] < dp[v];
});
}
void dfs1(int now, int pre) {
for(auto &i : g[now]) {
if(i == pre) {
continue;
}
if(dp[i])ans.push_back(now);
dfs1(i, now);
}
if(!dp[now])ans.push_back(now);
}
void init(int n) {
for(int i = 1;i <= n;i ++) {
g[i].clear();
dp[i] = 0;
}
ans.clear();
}
void solve()
{
cin >> n >> st >> ed;
init(n);
for(int i = 1;i < n;i ++) {
int u, v;cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(st, 0);
dfs1(st, 0);
ans.push_back(ed);
for(auto &i : ans) {
cout << i << ' ';
}
cout << '\n';
}
D1. Infinite Sequence (Easy Version)
思维难度远小于 C 题,我们可以发现,对于一个偶数
我们采取递归实现,使用一个
int get(int x) {
if(x <= n)return pre[x];
if(x & 1) {
return pre[n];
} else {
return get(x / 2) ^ pre[n];
}
}
void solve()
{
cin >> n >> l >> r;
for(int i = 1;i <= n;i ++)cin >> a[i];
for(int i = 1;i <= n;i ++)pre[i] = pre[i - 1] ^ a[i];
if(n % 2 == 0) {
n ++;
a[n] = pre[n / 2];
pre[n] = pre[n - 1] ^ a[n];
}
if(l <= n) {
cout << a[l] << '\n';
return;
}
cout << get(l / 2) << '\n';
}
作者: 天天超方的
出处: https://www.cnblogs.com/TianTianChaoFangDe
关于作者:ACMer,算法竞赛爱好者
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显醒目位置给出, 原文链接 如有问题, 可邮件(1005333612@qq.com)咨询.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架