9.15 校内模拟赛 题解报告
9.15 校内模拟赛 题解报告
扯
把对 zxsoul 神仙的膜拜打在最前面
福利场 + 图论专场
T1 并查集维护子树大小
T2 不知道考的啥的水题
T3 分层图
大概这场考试就是这样...
关于考试过程以及一些题外话
大概是遇到一场能做的 在 zxsoul 的无意提示下喜提 AK
这次的题确实是水...
开考从 T1 开始看... 读完题发现好像可以直接写...
想了一下 可以倒序建边 然后好像就做完了...
以为自己想得太简单了... 就先扔掉了 跑去看 T2
T2 好像可以直接倒序建图然后遍历一遍就行了...
是不是想的太简单了... 不管了 看 T3
T3 送了五十的最短路... 后面的分没什么思路
然后回头把 T1 写了 顺便把 T2 也写了...
然后把 T3 的五十写了...
害怕 T1 不对 然后开始想 T1 的暴力怎么写...
发现好像要写树剖 思索了一下还是写了(因为太闲了)
然后开始拍...
T2 实在想不出怎么写暴力... 毕竟感觉自己写的就是暴力 然后就没拍...
继续开 T3
一直没什么进展... 直到十一点的时候(还剩半个小时...)
(BS 旁边)zxsoul: 这 T3 必是个分层图...
嗯?
分层图... 好像可以写...
不到二十分钟码完造数据卡了一下好像没什么问题 就交了
然后? 然后就过了
这就 AK 了???
得分情况
100 + 100 + 100 = 300
传说中的福利场
题解
T1 大魔法师
暴力比正解都难写...
考虑每条边在那些组合里面会成为最大值 统计这种组合的个数即可
首先考虑最大的一条边 不难发现所有经过这条边的路径取值均为这条边 而经过这条边的路径数量则为这条边两边的点数的乘积 统计过这条边之后 所有经过这条边的路径都不需要再统计了 所以可以直接把这条边删掉 然后继续统计删除后两棵树的边
具体实现的话将边从大到小排序 依次删除 统计这条边连接的两点所在子树的大小 计入答案即可
但是这样子树的大小不太好维护 所以考虑从小到大排序 倒序加边 显然这与删边是等价的 并查集维护即可
代码
/*
Source: 大魔法师
首先有个五十的暴力 n 方枚举点对
考虑正解
从大到小枚举删边 维护子树节点数量即可
节点数量比较难搞 考虑维护倒序加边的过程
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#define int long long
#define pt putchar(' ')
#define pn putchar('\n')
#define Abs(x) ((x) < 0 ? -(x) : (x))
#define Max(x, y) ((x) > (y) ? (x) : (y))
#define Min(x, y) ((x) < (y) ? (x) : (y))
#define Swap(x, y) ((x) ^= (y) ^= (x) ^= (y))
/*----------------------------------------------------------*/
const int A = 1e4 + 7;
const int B = 2e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 999999937;
const int INF = 0x3f3f3f3f;
/*----------------------------------------------------------*/
inline void File() {
freopen("magic.in", "r", stdin);
freopen("magic.out", "w", stdout);
}
/*----------------------------------------------------------*/
int n, siz[B], fa[B], ans;
struct node {int u, v, w;} a[B];
struct edge {int v, w, nxt;} e[B << 1];
int head[B], ecnt;
/*----------------------------------------------------------*/
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * f;
}
void Print(int x) {if(x < 0) putchar('-'), x = -x; if(x > 9) Print(x / 10); putchar(x % 10 ^ 48);}
/*----------------------------------------------------------*/
void add_edge(int u, int v, int w) {e[++ecnt] = (edge){v, w, head[u]}; head[u] = ecnt;}
int find(int x) {return fa[x] == x ? x : fa[x] = find(fa[x]);}
bool cmp(node x, node y) {return x.w < y.w;}
void Main() {
File();
n = read();
for(int i = 1; i ^ n + 1; ++i) fa[i] = i, siz[i] = 1;
for(int i = 1, x, y, z; i ^ n; ++i)
a[i] = (node){x = read(), y = read(), z = read()}, add_edge(x, y, z), add_edge(y, x, z);
std::sort(a + 1, a + n, cmp);
for(int i = 1; i ^ n; ++i)
{
int x = find(a[i].u), y = find(a[i].v), w = a[i].w;
fa[x] = y; ans = (ans + siz[x] * siz[y] % mod * w % mod) % mod; siz[y] += siz[x];
}
Print(ans);
}
/*----------------------------------------------------------*/
signed main() {Main(); return 0;}
T2 捷径
这场考试里最水的一道题
建反图 倒着贪即可
容易发现每个点第一次被搜到的时候是最优的 打标记 复杂度为 \(O(n)\) 的
/*
Source: 捷径
直接建图 然后倒着扫一遍即可
*/
#include<cstdio>
#include<cstring>
#define pt putchar(' ')
#define pn putchar('\n')
#define Abs(x) ((x) < 0 ? -(x) : (x))
#define Max(x, y) ((x) > (y) ? (x) : (y))
#define Min(x, y) ((x) < (y) ? (x) : (y))
#define Swap(x, y) ((x) ^= (y) ^= (x) ^= (y))
/*----------------------------------------------------------*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*----------------------------------------------------------*/
inline void File() {
freopen("contra.in", "r", stdin);
freopen("contra.out", "w", stdout);
}
/*----------------------------------------------------------*/
int n, m, ans[B];
struct edge {int v, nxt;} e[B];
int head[B], ecnt;
bool vis[B];
/*----------------------------------------------------------*/
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * f;
}
void Print(int x) {if(x < 0) putchar('-'), x = -x; if(x > 9) Print(x / 10); putchar(x % 10 ^ 48);}
/*----------------------------------------------------------*/
void add_edge(int u, int v) {e[++ecnt] = (edge){v, head[u]}; head[u] = ecnt;}
void dfs(int u, int tp) {
ans[u] = tp; vis[u] = 1;
for(int i = head[u], v; i; i = e[i].nxt) if(!vis[v = e[i].v]) dfs(v, tp);
}
void Main() {
File();
n = read(); m = read();
for(int i = 1, x, y; i ^ m + 1; ++i) x = read(), y = read(), add_edge(y, x);
for(int i = n; i; --i) if(!vis[i]) dfs(i, i);
for(int i = 1; i ^ n + 1; ++i) Print(ans[i]), pt;
}
/*----------------------------------------------------------*/
signed main() {Main(); return 0;}
T3 过路费
建分层图跑最短路即可
代码
/*
Source: 过路费
*/
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define int long long
#define pt putchar(' ')
#define pn putchar('\n')
#define pr std::pair <int, int>
#define mk std::make_pair
#define Abs(x) ((x) < 0 ? -(x) : (x))
#define Max(x, y) ((x) > (y) ? (x) : (y))
#define Min(x, y) ((x) < (y) ? (x) : (y))
#define Swap(x, y) ((x) ^= (y) ^= (x) ^= (y))
/*----------------------------------------------------------*/
const int A = 1e4 + 7;
const int B = 5e4 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*----------------------------------------------------------*/
inline void File() {
freopen("pass.in", "r", stdin);
freopen("pass.out", "w", stdout);
}
/*----------------------------------------------------------*/
int n, m, K, S, T, dis[2][A * 13], ans = INF;
struct edge {int v, w, nxt;} e[C << 2];
int head[A * 13], ecnt;
bool vis[A * 13];
std::priority_queue <pr> q;
/*----------------------------------------------------------*/
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * f;
}
void Print(int x) {if(x < 0) putchar('-'), x = -x; if(x > 9) Print(x / 10); putchar(x % 10 ^ 48);}
/*----------------------------------------------------------*/
void add_edge(int u, int v, int w) {e[++ecnt] = (edge){v, w, head[u]}; head[u] = ecnt;}
void dijk(int s, bool op) {
for(int i = 0; i ^ n + 1; ++i) dis[op][i] = INF, vis[i] = 0;
dis[op][s] = 0; q.push(mk(0, s));
while(!q.empty())
{
int u = q.top().second; q.pop(); if(vis[u]) continue; vis[u] = 1;
for(int i = head[u], v; i; i = e[i].nxt) if(dis[op][v = e[i].v] > dis[op][u] + e[i].w)
dis[op][v] = dis[op][u] + e[i].w, q.push(mk(-dis[op][v], v));
}
}
void dijk2(int s, bool op) {
dis[op][s] = 0; q.push(mk(0, s));
while(!q.empty())
{
int u = q.top().second; q.pop(); if(vis[u]) continue; vis[u] = 1;
for(int i = head[u], v; i; i = e[i].nxt) if(dis[op][v = e[i].v] > dis[op][u] + e[i].w)
dis[op][v] = dis[op][u] + e[i].w, q.push(mk(-dis[op][v], v));
}
}
void work1() {dijk(S, 0); Print(dis[0][T]);}
void work2() {
dijk(S, 0); dijk(T, 1);
for(int i = 1; i <= 2 * m; i += 2)
{
int u = e[i + 1].v, v = e[i].v, tmp = Min(dis[0][u] + dis[1][v], dis[0][v] + dis[1][u]);
ans = Min(ans, tmp);
}
Print(ans);
}
void work3() {
for(int i = 1; i ^ m + 1; ++i)
{
int x = read(), y = read(), z = read();
add_edge(x, y, z); add_edge(y, x, z);
for(int j = 1; j ^ K + 1; ++j)
{
add_edge(x + j * n, y + j * n, z);
add_edge(y + j * n, x + j * n, z);
add_edge(x + (j - 1) * n, y + j * n, 0);
add_edge(y + (j - 1) * n, x + j * n, 0);
}
}
for(int i = 0; i ^ K + 1; ++i) add_edge(T + i * n, (K + 1) * n + 1, 0);
memset(dis, 63, sizeof dis); memset(vis, 0, sizeof vis); dijk2(S, 0);
Print(dis[0][(K + 1) * n + 1]);
}
void Main() {
File();
n = read(); m = read(); K = read(); S = read(); T = read();
work3(); return ;
if(K != 0 && K != 1) {work3(); return ;}
for(int i = 1, x, y, z; i ^ m + 1; ++i)
x = read(), y = read(), z = read(), add_edge(x, y, z), add_edge(y, x, z);
if(!K) work1();
else if(K == 1) work2();
// else work3();
// work3();
}
/*----------------------------------------------------------*/
signed main() {Main(); return 0;}
后记
梦想太抽象, 现实太真实, 十七岁了, 祝自己生日快乐. —— 2021.9.15