9.15 校內模擬賽 題解報告
9.15 校內模擬賽 題解報告
目錄扯
\[\huge \%\%\%\%\%\ stO\ \ Zxsoul\ \ Orz\ \ \%\%\%\%\% \]把對 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