省流:通过 A,B,D,C 拼尽全力无法做出。rk2292,+26 变为 1554 specialist(实际上我应该在这场比赛就已经 >=1600 expert 了,因为每次 div.2 我都能涨 100+pts)。
默哀 Timmyliuyunxi 以 candidate master 的理论极强实力打出了 rk2031 的成绩。-79,1994->1915 有些危险。
C 题果然是妙妙题,还得多练。
B 题卡思路卡的太久了。D 题调的太久了。
本场最重要的能力:注意力。
A.The Play Never Ends
https://codeforces.com/contest/2071/problem/A
赛时靠观察样例,注意到输出 YES 当且仅当 k ≡ 1 ( m o d 3 ) k \equiv 1(\bmod 3) k≡1(mod3)。一交过了。
请叫我猜结论大师\kx
给出严谨性证明(感性?):
易得,一旦第一场比赛胜负已定,接下来的比赛就完全可以预料了。(可以自由的规定谁输谁赢)
于是不妨假设如果 Sosai \text {Sosai} Sosai 赢得了 Fofo \text {Fofo} Fofo 观战的第一场比赛。
无论谁在第二场比赛中获胜, Hohai \text {Hohai} Hohai 都无法继续参加第三场比赛(即使他在第二场比赛中获胜),因为他已经连续参加了两场比赛。
同样, Fofo \text {Fofo} Fofo 也无法参加第四场比赛,因为无论比赛结果如何,他都已经连续参加了两场比赛。
因此,对于任何形如 3 x + 1 3x+1 3x+1 的 k k k, 福福都不能在第 k k k 场比赛中旁观。
证毕。
B.Perfecto
https://codeforces.com/contest/2071/problem/A
构造题我还是太菜了。
写一下心路历程:
-
构造题传统的面向数据,先观察样例。
-
发现 n = 1 n=1 n=1 时是 -1,哦哦哦,所有数的总和不能是完全平方数。
-
发现 n = 4 n=4 n=4 是若干递增的偶数排上若干递增的奇数,考虑这样构造。然后发现 n = 5 n=5 n=5 时是对的!
-
信心满满的提交,Wrong answer on pretest 2。
-
炸了,B 都不能一遍过。发现 n = 6 n=6 n=6 时这种方法坠机,考虑其他方法。
-
试着打了一下 n = 6 n=6 n=6 的表,发现情况数挺多。排列?我想到了什么?随机化?
-
于是使用
random_shuffle()
对排列进行打乱,每次判断一下是否满足条件即可。优化了一下常数,发现第一位一定可以是 2 2 2。 -
一交,过了。之后就再也没有被 hack 过。
发现石老师的方法明显简洁一些啊!不过代码略微长了一点。拜谢 Master 巨佬。
#include <bits/stdc++.h>
#define int long long
using namespace std;
int t;
const int N = 500010;
int a[N];
signed main() {
cin >> t;
while (t--) {
int n;
cin >> n;
int x = n * (n + 1) / 2;
int y = sqrt(x);
if (y * y == x) {//先判断
cout << "-1\n";
continue;
}
for (int i = 1; i <= n; i++)
a[i] = i;
a[1] = 2, a[2] = 1;//常数优化
while (1) {
bool f = 1;
random_shuffle(a + 2, a + n + 1);//随机化
int cnt = 0;
for (int i = 1; i <= n; i++) {
cnt += a[i];
int y = sqrt(cnt);
if (y * y == cnt) {
f = 0;
break;
}
}
if (f == 1) {
for (int i = 1; i <= n; i++)
cout << a[i] << " ";
cout << endl;
break;//找到就退出
}
}
}
return 0;
}
C.Trapmigiano Reggiano
比赛结束前一分钟写完,交上去不过,狂怒。
才发现自己的方法不是正解,笑抽了。
原因:以 s t st st 为树根,和正解的以 e n en en 为树根恰好相反。
妙妙题。
一点也不易得
s
t
st
st 为树根时这个问题有点难解,考虑以
e
n
en
en 为根。
插叙:前三题不涉及很高级的算法,需要的是数学能力。想到 s t st st 和 e n en en 的路径长度时竟然没有想到将 e n en en 作为树根,可太强了/cf。
注意到当从深度最高的结点一直循环到深度低的结点时,
s
t
st
st 的位置一定是
e
n
en
en。
然后就发现没有可能是 − 1 -1 −1,纯纯诈骗。
于是这道题就做完了。
#include <bits/stdc++.h>
using namespace std;
int t;
int n, st, en;
const int N = 100010;
int dep[N];
vector<int> v[N], p[N];//v表示邻接表,p表示每一个深度对应的点编号
void dfs(int u, int pre) {
dep[u] = dep[pre] + 1;
p[dep[u]].push_back(u);//记录
for (auto i : v[u])
if (i != pre)
dfs(i, u);
}
int main() {
cin >> t;
while (t--) {
cin >> n >> st >> en;
for (int i = 1; i <= n; i++)
v[i].clear(), dep[i] = 0, p[i].clear();
for (int i = 1; i < n; i++) {
int x, y;
cin >> x >> y;
v[x].push_back(y);
v[y].push_back(x);
}
dfs(en, 0);//核心
for (int i = n; i >= 1; i--)
for (auto j : p[i])
cout << j << " ";//从深度大的点进行遍历
cout << endl;
}
return 0;
}
D1.Infinite Sequence (Easy Version)
https://codeforces.com/contest/2071/problem/D1
递归+分类讨论。
发现当 m > n m>n m>n,且 m m m 为偶数时, a m a_m am 和 a m + 1 a_{m+1} am+1 会相同,也就是 xor 起来会抵消掉,变成 0 0 0。
于是只需要分类讨论一下 x x x 和 n n n 的奇偶性即可。
#include <bits/stdc++.h>
#define int long long
using namespace std;
int t;
const int N = 200010;
int a[N];
int n, l, r;
int sum[N];//异或前缀和
int get(int x) {//求a_1 xor a_2 xor a_x
if (x <= n)
return sum[x];
if (x % 2 == 1) {
if (n % 2 == 1)
return sum[n];//全部抵消掉了
else
return sum[n] ^ get((n + 1) / 2);
} else {
if (n % 2 == 1)
return sum[n] ^ get(x / 2);
else
return sum[n] ^ get(x / 2)^get((n + 1) / 2);
}
}
int get_ans(int x) {//计算 a_x
if (x <= n)
return a[x];
else
return get(x / 2);
}
signed main() {
cin >> t;
while (t--) {
cin >> n >> l >> r;
for (int i = 1; i <= n; i++)
cin >> a[i], sum[i] = sum[i - 1] ^ a[i];
cout << get_ans(l) << endl;
}
return 0;
}
因为浪费时间过多,错过场切 D2(提高+/省选-),可耻!!!
D2 使用 data structures 维护即可。