2024.12.12 CW 模拟赛
T1
先贴个暴力代码.
#include "iostream"
#include "algorithm"
#include "cstring"
using namespace std;
constexpr int N = 2e3 + 1, M = 4e5 + 1;
inline int read()
{
int x = 0;
char ch = getchar();
while (ch < '0' or ch > '9')
ch = getchar();
while (ch >= '0' and ch <= '9')
x = x * 10 + ch - 48, ch = getchar();
return x;
}
int n, m, Q;
basic_string<int> e[N];
bool vis[N][N], connect[N][N];
void init()
{
n = read(), m = read(), Q = read();
for (int i = 1; i <= m; ++i)
e[read()].push_back(read());
}
void dfs(int u, int s)
{
vis[s][u] = connect[s][u] = 1;
for (int v : e[u])
{
if (vis[s][v])
continue;
dfs(v, s);
}
}
int f, ans;
bool use[N];
void deal(int u, int t, int stp)
{
use[u] = 1;
if (stp == 1)
ans = u;
if (u == t)
return;
int nxt = 1e9;
for (int v : e[u])
if (connect[v][t])
nxt = min(nxt, v);
if (use[nxt])
return f = 0, void();
deal(nxt, t, stp - 1);
}
void print(int x)
{
if (x < 0)
x = -x, putchar('-');
static int sta[35];
int top = 0;
do
{
sta[top++] = x % 10, x /= 10;
} while (x);
while (top)
putchar(sta[--top] + 48);
}
void calculate()
{
for (int i = 1; i <= n; ++i)
dfs(i, i);
while (Q--)
{
int s = read(), t = read(), k = read();
if (!connect[s][t])
{
print(-1);
putchar('\n');
continue;
}
f = 1, ans = -1;
deal(s, t, k);
if (!f)
print(-1);
else
print(ans);
putchar('\n');
memset(use, 0, sizeof use);
}
}
void solve()
{
init();
calculate();
}
int main()
{
solve();
return 0;
}
居然过了.
如果一定存在理想路径.
只需要将边按照字典序排序, 将询问离线, 按照起始点排序, 然后依次从每个点出发沿字典序最?的点遍历图即可, 更新答案即可.
时间复杂度 \(\mathcal{O}(nm)\).
接下来考虑哪些情况不存在理想路径:
-
- 无法到达, 先 dfs 一遍判断全局连通性即可.
-
- 对于任意路径都存在比其字典序更小的路径.
对于第 2 种情况, 即当按照字典序访问边时, 如果先出现环, 则之后从环上点出发找到的点一律均无理想路径.
T2
算法
素数筛, 质因数分解.
思路
因为 \((\sqrt{A}+\sqrt{B})^2=C\), 展开不好处理.
故可以考虑将两边同时开方, 得到:
\[\sqrt{A}+\sqrt{B}=\sqrt{C}
\]
这说明什么?
若将根式化简后两数的最简根式不同, 那么一定不能合成一个根式.
所以不妨令 \(\sqrt{A}=p \sqrt{x},\ \sqrt{B}=q \sqrt{x}\).
其中 \(\sqrt{x}\) 为最简根式.
故又有以下约束:
\[p^2 x \le n,\ q^2 x \le m
\]
考虑枚举 \(x\), 当 \(x\) 确定了, \(p,\ q\) 的范围也就确定了.
怎么判断 \(\sqrt{x}\) 是否为最简根式呢?
只需要枚举 \(\sqrt{x}\) 内的素数进行试除即可,
如果某个素数的幂 \(\ge 2\), 那么一定不是最简根式.
代码
#include "iostream"
#include "cmath"
using namespace std;
constexpr int N = 2e6 + 10;
int n, m, mn;
int p[N], cnt = 0;
bool vis[N];
void init()
{
cin >> n >> m;
mn = min(n, m);
for (int i = 2; i <= mn; ++i)
{
if (!vis[i])
p[++cnt] = i;
for (int j = 1; i * p[j] <= mn and j <= cnt; ++j)
{
vis[i * p[j]] = 1;
if (!(i % p[j]))
break;
}
}
}
void calculate()
{
long long ans = 0;
for (int i = 1; i <= mn; ++i)
{
int tmp = i, f = 1, x, y;
for (int j = 1; j <= cnt and p[j] * p[j] <= tmp; ++j)
if (!(tmp % p[j]))
{
int tot = 0;
while (!(tmp % p[j]))
tmp /= p[j], ++tot;
if (tot >= 2)
{
f = 0;
break;
}
}
if (f)
{
x = floor(sqrt(1.0 * n / i));
y = floor(sqrt(1.0 * m / i));
ans += 1ll * x * y;
}
}
cout << ans << '\n';
}
void solve()
{
init();
calculate();
}
signed main()
{
solve();
return 0;
}
T3
原题链接
题目要求支持两种操作:
-
- 单点修改.
-
- 将 \(\le x\) 的数均修改成 \(x\).
假设没有单点修改, 那么就只需要取最大的 \(x\) 即可.
否则对于每个点, 我们要取最后一次单点修改后区间操作的最大值与最后一次单点修改的值相比较, 取较大的.
我们可以记录每个点最后一次单点修改的时间, 在预处理所有时间点之后里区间操作的值后缀中最大的值.
总时间复杂度 \(\mathcal{O}(n)\).

浙公网安备 33010602011771号