比赛链接
D.
给你n个数,问你最少取走多少个后剩下的n个能组成1~n的有序数列。
思路:
找原来n个数中最长的1~n的序列的长度,用n减去这个长度即可。
E.
给你一个n(0 <= n <= 1e18), 问你n * (n - 2) * (n - 4) * …的值是多少。
其中你可以认为n = 0和n = 1时的值都是1。现在问你乘积结尾有多少个0。
思路:
此题是求 !n 结尾有多少个0的翻版,还是要看5的倍数和偶数的乘积对结尾0的贡献。
当n为奇数时,显然结尾没有0。
当n为偶数时,只有10的倍数对结尾的0有贡献,不存在5,所以每次算出有多少个5的贡献,还要除以2。
至于为什么除以2:
5->0
10->1
15->1
20->2
…
也算是一道经典题目了, 别忘了开long long。
#include <bits/stdc++.h>
#define mp make_pair
#define mt make_tuple
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define forn(i, n) for (int i = 0; i < (int)(n); ++i)
#define for1(i, n) for (int i = 1; i <= (int)(n); ++i)
#define ford(i, a, b) for (int i = (int)(a); i >= (int)b; --i)
#define fore(i, a, b) for (int i = (int)(a); i <= (int)(b); ++i)
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define ms(x, y) memset(x, y, sizeof(x))
using namespace std;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector<vi> vvi;
typedef long long i64;
typedef vector<i64> vi64;
typedef vector<vi64> vvi64;
typedef pair<i64, i64> pi64;
typedef double ld;
template<class T> bool uin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool uax(T &a, T b) { return a < b ? (a = b, true) : false; }
i64 n;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.precision(10);
cout << fixed;
#ifdef LOCAL_DEFINE
freopen("in", "r", stdin);
#endif
cin >> n;
if (n & 1) {
cout << 0 << '\n';
return 0;
}
i64 sum = 0;
while (n /= 5) {
sum += n / 2;
}
cout << sum << '\n';
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}
F.
F题算是对我最有收获的一题了,我还出了一组hack数据,可以hack我自己的ac代码。数据如下:
6 1 3
1 2
2 3
2 4
4 5
5 6
正确输出应该是1,我的某一ac代码输出是3。我的水过ac代码
有n个点,有两个分别站在u,v两点,下面给出n-1条边(说明没有环,所有点都可以互相到达)。u的目标是尽可能的远离v(让他们俩相遇的时间变长),v的目标是尽可能的靠近u(让他们俩相遇的时间变短),u先手,v后手,每次u或v都不能不走,一定要走到与自己相邻的那个点。现在问你v走了多少步。
思路:
现在目标点(u要去的点),u到达目标点的时间肯定要比v严格小,等于不行(我的水过代码),至于为什么看hack数据就明白了,然后要找b到这个点的时间最长的那个点作为目标点,然后可以证明(画两种情况的例子)答案就是max(b到某个点的距离(目标点)) - 1。
#include <bits/stdc++.h>
#define mp make_pair
#define mt make_tuple
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define forn(i, n) for (int i = 0; i < (int)(n); ++i)
#define for1(i, n) for (int i = 1; i <= (int)(n); ++i)
#define ford(i, a, b) for (int i = (int)(a); i >= (int)b; --i)
#define fore(i, a, b) for (int i = (int)(a); i <= (int)(b); ++i)
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define ms(x, y) memset(x, y, sizeof(x))
using namespace std;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector<vi> vvi;
typedef long long i64;
typedef vector<i64> vi64;
typedef vector<vi64> vvi64;
typedef pair<i64, i64> pi64;
typedef double ld;
template<class T> bool uin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool uax(T &a, T b) { return a < b ? (a = b, true) : false; }
const int maxn = (int)1e5 + 1000;
int n, u, v, a[maxn], b[maxn], vis[maxn];
vvi g(maxn);
void dfs1(int now, int step) {
for (auto it : g[now]) {
if (a[it] == -1) {
a[it] = step + 1;
dfs1(it, step + 1);
}
}
}
void dfs2(int now, int step) {
for (auto it : g[now]) {
if (b[it] == -1) {
b[it] = step + 1;
dfs2(it, step + 1);
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.precision(10);
cout << fixed;
#ifdef LOCAL_DEFINE
freopen("in", "r", stdin);
#endif
ms(a, -1); ms(b, -1);
cin >> n >> u >> v;
forn(i, n - 1) {
int e1, e2;
cin >> e1 >> e2;
g[e1].pb(e2);
g[e2].pb(e1);
}
a[u] = 0;
dfs1(u, 0);
b[v] = 0;
dfs2(v, 0);
int ans = -1;
for1(i, n) {
if (a[i] < b[i]) {
ans = max(ans, b[i]);
}
}
cout << (ans - 1) << '\n';
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}
我看评论区的老哥发了一道cf上类似的题目也去做了一下,也正是因为这道题我才发现我之前的代码是水过的 -_-||。
相似的题目:题目链接
题目大意和上面基本一样,不一样的一点就是轮到每个人的那回合那个人可以选择不走,而不是像atcoder的那题一样一定要走到旁边的某个点,每个人走都是一回合,要求有多少回合数。所以答案就变成了max(b到某个点的距离(目标点)) * 2。如果像atcoder那题问的是v要走多少步,那就是max(b到某个点的距离(目标点))。
注意:一定要在u到达的时间严格小于v到达的时间的那些点里面选, 选v最晚到达的。
#include <bits/stdc++.h>
#define mp make_pair
#define mt make_tuple
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define forn(i, n) for (int i = 0; i < (int)(n); ++i)
#define for1(i, n) for (int i = 1; i <= (int)(n); ++i)
#define ford(i, a, b) for (int i = (int)(a); i >= (int)b; --i)
#define fore(i, a, b) for (int i = (int)(a); i <= (int)(b); ++i)
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define ms(x, y) memset(x, y, sizeof(x))
using namespace std;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector<vi> vvi;
typedef long long i64;
typedef vector<i64> vi64;
typedef vector<vi64> vvi64;
typedef pair<i64, i64> pi64;
typedef double ld;
template<class T> bool uin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool uax(T &a, T b) { return a < b ? (a = b, true) : false; }
const int maxn = 2 * (int)1e5 + 1000;
int n, x, a[maxn], b[maxn];
vvi g(maxn);
void dfs1(int now, int step) {
for (auto it : g[now]) {
if (a[it] == -1) {
a[it] = step + 1;
dfs1(it, step + 1);
}
}
}
void dfs2(int now, int step) {
for (auto it : g[now]) {
if (b[it] == -1) {
b[it] = step + 1;
dfs2(it, step + 1);
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.precision(10);
cout << fixed;
#ifdef LOCAL_DEFINE
freopen("in", "r", stdin);
#endif
ms(a, -1); ms(b, -1);
cin >> n >> x;
--x;
forn(i, n - 1) {
int e1, e2;
cin >> e1 >> e2;
--e1; --e2;
g[e1].pb(e2);
g[e2].pb(e1);
}
a[0] = 0;
dfs1(0, 0);
b[x] = 0;
dfs2(x, 0);
int p, max_num = -1;
forn(i, n) {
if (b[i] < a[i]) {
max_num = max(max_num, a[i]);
}
}
cout << max_num * 2 << '\n';
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}
非常愉快的一次补题体验 : >