2020.5.30 解题报告
2020.5.30
答题情况
总成绩 : 280 , 排名 : 94 / 1097
T1 : 100 T2 : 100 T3 : 80 T4:0
各题目分析
题目 1 :
预估成绩 : 100 实际成绩 : 100 考试用时 : 2:00 ~ 2:10
签到水题。
题目 2 :
预估成绩 : 100 实际成绩 : 100 考试用时 : 2:10 ~ 3:00
黄题难度。
手生了,应该能在30min之内调出来的。
题目 3 :
预估成绩 : 80 实际成绩 : 80 考试用时 : 3:10 ~ 5:30
先写了暴力,之后死推性质,拿了80。
题目 3 :
预估成绩 : 10 实际成绩 : 0 考试用时 : 5:30 ~ 6:00
还有半个小时rush了一波。
rua过样例电脑卡了没交上。
题目解析
T1
输出 \(2 \times \mid O \mid - 1\) 即可。
注意ull不溢出。
T2
先 dfs 判断给出图形是否全部由链组成。
满足下列条件之一的联通块即为链。
- 大小为1。
- 两端点只有一个相邻的位置,其他位置都恰好有两个相邻位置
若图中出现非链的联通块,则该图不合法。
dfs找链的个数。
对于一条链,可以直接将其转化为做一个数列。现在需要往数列上填数,使相邻的数互不相同。
则除第一个位置填k种外,其他位置均填k-1种,一条链的贡献即为 \(k \times (l - 1) ^ {k - 1}\)
T3
什么样子的分数可以表示为十进制有限小数?
约分后,分母只含 2, 5 两种因子的分数可以。
40 pts:
直接 \(n ^ 2\) 两重循环,暴力模拟即可。
80 pts:
观察定义,先不考虑分子分母约分。
发现 当分母只含2, 5 两种因子时,分子取何值均满足条件。
考虑反向约分,使分母分子都乘上一个数,即为如下形式:
尝试先枚举 c。
那么,b 的取值依然是 [1, ⌊𝑛/𝑐⌋] 的任何数,而 𝑎 的取值就变为了 [1, ⌊𝑛/𝑐⌋] 中任何只含 2, 5 两种因子的数。
发现,𝑎 的取值的个数随着 𝑐 的增大而单调减小,所以可以在总共 𝑂(𝑛) 的时间中计算。
也就是,对于每个 𝑐,记合法的 𝑎 的个数为 𝑑,则它对答案的贡献为 \(𝑑\times ⌊𝑛/𝑐⌋\) 。
时间复杂度依然是 \(𝑂(𝑛)\)。
100 pts:
使用整除分块 + 容斥原理优化上述过程。
T4
10pts
爆搜枚举走过的路径,模拟运动状况。
答案比较小,可乱搞过掉。
100 pts
我们可以想到,敌人有很多是重复的,所以每一个位置上只留一个敌人即可。
然后,我们可以贪心的想:走到一个位置以后,等着别人来送死。
如何求出这个位置?
显然该位置在树的直径的中点处。
代码实现
T1 :
考场代码(正解)
//
/*
By:Luckyblock
*/
#include <cstdio>
#include <ctype.h>
#include <iostream>
#define min std::min
#define max std::max
#define ll long long
#define ull unsigned long long
//=============================================================
ll O;
ull O1;
//=============================================================
inline int read() {
int f = 1, w = 0; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
return f * w;
}
//=============================================================
int main() {
std :: cin >> O;
if (O <= 0) {
printf("0");
return 0;
}
O1 = O;
std :: cout << (O1 - 1) * 2 + 1;
return 0;
}
T2:
考场代码(正解)
//
/*
By:Luckyblock
*/
#include <cstdio>
#include <ctype.h>
#include <cstring>
#include <algorithm>
#define min std::min
#define max std::max
#define ll long long
const int kMaxn = 1010;
const int mod = 998244353;
const int ex[5] = {- 1, 0, 1, 0};
const int ey[5] = {0, - 1, 0, 1};
//=============================================================
ll n, m, k, ans = 1;
int line_num, num1, num2, size, num[kMaxn][kMaxn], lth[kMaxn << 6];
char map[kMaxn][kMaxn];
bool vis[kMaxn][kMaxn];
//=============================================================
inline ll read() {
ll f = 1, w = 0; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
return f * w;
}
void Dfs(int x, int y) {
size ++;
vis[x][y] = true;
for (int i = 0; i < 4; i ++) {
if (map[x + ex[i]][y + ey[i]] == 'O') {
num[x][y] ++;
if (! vis[x + ex[i]][y + ey[i]]) {
Dfs(x + ex[i], y + ey[i]);
}
}
}
if (num[x][y] > 2) num2 ++;
if (num[x][y] == 1) num1 ++;
}
bool RoomJudge() {
for (int i = 1; i <= n; ++ i) {
for (int j = 1; j <= m; ++ j) {
if (map[i][j] == 'O' && ! vis[i][j]) {
num1 = size = num2 = 0;
Dfs(i, j);
lth[++ line_num] = size;
if (size == 1) num1 += 2;
if (num1 != 2 || num2) return true;
}
}
}
return false;
}
ll qpow(ll x, ll y) {
ll ret = 1;
while (y) {
if (y & 1) ret = ret * x % mod;
y >>= 1, x = x * x % mod;
}
return ret;
}
//=============================================================
int main() {
n = read(), m = read(), k = read();
for (int i = 1; i <= n; ++ i) {
scanf("%s", map[i] + 1);
}
if (RoomJudge()) {
printf("0\n");
return 0;
}
for (int i = 1; i <= line_num; i ++) {
ans *= k * qpow(k - 1, lth[i] - 1) % mod;
ans %= mod;
}
printf("%lld\n", ans);
}
/*
1 1 2
O
*/
T3:
考场代码
//
/*
By:Luckyblock
*/
#include <map>
#include <queue>
#include <cstdio>
#include <ctype.h>
#include <algorithm>
#define min std::min
#define max std::max
#define ll long long
const int kMaxn = 1e7 + 10;
//=============================================================
ll n, num1, num2, ans;
bool flag[kMaxn];
int q1[kMaxn], q2[kMaxn], sum[kMaxn];
//=============================================================
inline ll read() {
ll f = 1, w = 0; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
return f * w;
}
//=============================================================
int main() {
n = read();
flag[2] = flag[5] = true;
q1[++ num1] = 1;
if (n >= 2) q1[++ num1] = 2;
if (n >= 5) q1[++ num1] = 5;
for (int i = 2; i <= num1; ++ i) {
int top = q1[i];
if (! flag[top * 2] && top * 2 <= n) {
q1[++ num1] = top * 2;
flag[top * 2] = true;
}
if (! flag[top * 5] && top * 5 <= n) {
q1[++ num1] = top * 5;
flag[top * 5] = true;
}
}
sum[0] = n;
for (int i = 2; i <= n; ++ i) {
if (i % 2 == 0 || i % 5 == 0) continue ;
q2[++ num2] = i;
sum[num2] += sum[num2 - 1] + (n / i);
}
std :: sort(q1 + 1, q1 + num1 + 1);
for (int i = 1, j = num2; i <= num1; i ++) {
while (q1[i] * q2[j] > n) j --;
ans += sum[j];
}
printf("%lld", ans);
return 0;
}
T4
考场代码
//
/*
By:Luckyblock
*/
#include <cstdio>
#include <ctype.h>
#include <cstring>
#include <algorithm>
const int kMaxn = 30;
//=============================================================
struct Edge {
int u, v, ne;
} e[kMaxn << 1];
int edge_num, head[kMaxn];
int n, m, k, x, ans = 114514, dep[kMaxn], fa[kMaxn];
int rest, pos[kMaxn], tmp[kMaxn];
bool kill[kMaxn], vis[kMaxn];
//=============================================================
inline int read() {
int f = 1, w = 0; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
return f * w;
}
void AddEdge(int u, int v) {
e[++ edge_num].u = u, e[edge_num].v = v;
e[edge_num].ne = head[u], head[u] = edge_num;
}
void Dfs1(int u) {
for (int i = head[u]; i; i = e[i].ne) {
if (! dep[e[i].v]) {
dep[e[i].v] = dep[u] + 1;
fa[e[i].v] = u;
Dfs1(e[i].v);
}
}
}
void Dfs(int time) {
if (time > ans) return ;
if (! rest) {
ans = std :: min (time, ans);
return ;
}
int cnt = 0;
for (int i = 1; i <= m; ++ i) {
if (! kill[i] && dep[pos[i]] - 1 <= k) {
rest --;
kill[i] = true;
tmp[++ cnt] = i;
}
}
for (int i = head[x]; i; i = e[i].ne) {
memset(dep, 0, sizeof (dep));
x = e[i].v;
dep[e[i].v] = 1;
Dfs1(e[i].v);
for (int j = 1; j <= m; ++ j) {
pos[j] = fa[pos[j]];
}
Dfs(time + 1);
}
for (int i = 1; i <= cnt; ++ i) {
rest ++;
kill[tmp[i]] = false;
}
}
//=============================================================
int main() {
n = read();
for (int i = 1; i < n; ++ i) {
int u = read(), v = read();
AddEdge(u, v), AddEdge(v, u);
}
rest = m = read();
for (int i = 1; i <= m; i ++) pos[i] = read();
k = read(), x = read();
dep[x] = 1;
Dfs1(x);
Dfs(0);
printf("%d\n", ans);
return 0;
}