2021,10,18 題解報告
阿新 • • 發佈:2021-10-19
寫在前面
\(T1\) 沒想出來,卒
T1
招待(entertain)
solution
對 \(W\) 進行三進位制拆分,每一位是一個砝碼。
如果第 \(i\) 位是 \(2\) 就將其進位(在該位置放一個物品),因為每個物品只有一個。
最後得到的一個 \(01\) 串就是放物品的最終狀態。
code
/* work by: Ariel_ Knowledge: Time: */ #include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<algorithm> #define int long long using namespace std; int read() { int x = 0, f = 1; char c = getchar(); while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();} return x * f; } int stc[200], sc, a[200], b[200], W, x; signed main(){ b[1] = 1; for (int i = 2; i <= 35; i++) b[i] = b[i - 1] * 3; W = read(); x = W; while(x) {stc[++sc] = x % 3, x /= 3;} for (int i = 1; i <= sc; i++) { stc[i + 1] += stc[i] / 3; stc[i] %= 3; if(stc[i] == 2) { stc[i + 1]++, stc[i] = 0; a[i] = true; } if(stc[i + 1] > 0) sc = max(i + 1, sc); } for (int i = 1; i <= sc; i++) if(stc[i] == 1) cout<<b[i]<<" "; puts(""); cout<<W<<" "; for (int i = 1; i <= sc; i++) if(a[i]) cout<<b[i]<<" "; puts(""); return 0; }
T2
novel
solution
資料範圍不大,分層圖直接碾過去了 = =。
正解是二分路徑的最大值,然後 \(bfs\) 判斷是否合法。
code
/* work by: Ariel_ Knowledge: Time: */ #include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; const int MAXN = 1e5 + 5; const int MAXM = 2e5 + 5; int read() { int x = 0, f = 1; char c = getchar(); while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();} return x * f; } int n, m, k, fa[MAXN], Ans = 0x3f3f3f3f; struct edge{int v, nxt, w;}e[MAXM << 1]; int head[MAXN], E; void add_edge(int u, int v, int w) { e[++E] = (edge) {v, head[u], w}; head[u] = E; } int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); } queue<int> q; int dis[MAXN]; void work(int s) { memset(dis, 0x3f, sizeof dis); dis[s] = 0, q.push(s); while(!q.empty()) { int u = q.front(); q.pop(); for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].v; if(dis[v] > max(dis[u], e[i].w)) { dis[v] = max(dis[u], e[i].w); if(v % n != 0) q.push(v); } } } } int main(){ freopen("novel.in", "r", stdin); freopen("novel.out", "w", stdout); n = read(), m = read(), k = read(); for (int i = 1; i <= n; i++) fa[i] = i; for (int i = 1; i <= m; i++) { int u = read(), v = read(), w = read(); add_edge(u, v, w), add_edge(v, u, w); for (int j = 1; j <= k; j++){ add_edge(u + (j - 1) * n, v + j * n, 0); add_edge(v + (j - 1) * n, u + j * n, 0); add_edge(u + j * n, v + j * n, w); add_edge(v + j * n, u + j * n, w); } if(find(u) != find(v)) fa[find(u)] = find(v); } if(find(1) != find(n)) {puts("-1"); return 0;} work(1); for(int i = 0; i <= k; i++) Ans = min(Ans, dis[n + n * k]); cout<<Ans; return 0; }
chen_怡's code
二分
code
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<stack> #include<algorithm> #include<map> #define int long long using namespace std; const int N = 1e3 + 9; const int M = 1e4 + 9; struct node{ int last; int to; int dis; }e[M<<1]; int n , m , k; int dis[N]; int head[N] , cnt; bool vis[N]; int l = 0 , r = 0; int ans = -1; int read() { int f = 1 , x = 0; char s = getchar(); while(s<'0' || s>'9'){if(s=='-')f=-1;s=getchar();} while(s>='0'&&s<='9'){x=(x<<1)+(x<<3)+(s^'0');s=getchar(); } return f*x; } void add(int from,int to,int dis) { e[++cnt].last = head[from]; e[cnt].to = to; e[cnt].dis = dis; head[from] = cnt; } bool check(int x) { queue<int> q; memset(dis,0x3f3f3f3f,sizeof(dis)); memset(vis,false,sizeof(vis)); dis[1] = 0; q.push(1); while(!q.empty()) { int u = q.front(); q.pop(); vis[u] = false; for(int i = head[u] ; i ; i = e[i].last) { int v = e[i].to; int w = e[i].dis; if(w <= x) { if(dis[v] > dis[u]) { dis[v] = dis[u]; if(!vis[v]) { q.push(v); vis[v] = true; } } } else if(w > x and dis[u] < k) { if(dis[v] > dis[u] + 1) { dis[v] = dis[u] + 1; if(!vis[v]) { q.push(v); vis[v] = true; } } } } } return dis[n] <= k; } signed main() { n = read(); m = read(); k = read(); for(int i = 1 ; i <= m ; i ++) { int u = read(); int v = read(); int w = read(); add(u,v,w); add(v,u,w); r = max(r , w); } while(l <= r) { int mid = (l + r) >>1; if(check(mid)) { ans = mid; r = mid - 1; } else l = mid + 1; } printf("%lld\n",ans); return 0; }
T3
solution
在 \([−100,100]\) 中二分得到 \(mid\),讓所有紅葉的年輕程度加上該 \(mid\) 值,跑 \(Kruskal\),直到得到最終結果;
發現修改權值之後會有重複的部分。
這個可以直接在排序的時候把紅色的邊放到前面就好了。
code
/*
work by: Ariel_
Knowledge:
Time:
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#define int long long
using namespace std;
const int MAXN = 500005;
const int MAXM = 100005;
int read() {
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
return x * f;
}
struct edge{
int w, cw, u, v, col;
bool operator < (const edge &rhs) const {
if(cw == rhs.cw) return col < rhs.col;
return cw < rhs.cw;
}
}e[MAXM];
int fa[MAXN], n, m, need;
int find(int x) {return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);}
int kruskal(int x) {
int cnt = 0, ret = 0;
for(int i = 1; i <= n; i++) fa[i] = i;
for(int i = 1; i <= m; i++){
if(!e[i].col) e[i].cw = e[i].w + x;
else e[i].cw = e[i].w;
}
sort(e + 1, e + m + 1);
for(int i = 1; i <= m; i++){
if(find(e[i].u) != find(e[i].v)){
fa[find(e[i].u)] = find(e[i].v);
if(!e[i].col) cnt++;
ret += e[i].cw;
}
}
return cnt >= need ? ret : -1;
}
int work(int l, int r) {
if(l == r) return l;
int mid = (l + r + 1) >> 1;
int x = kruskal(mid);
if(x == -1) return work(l, mid - 1);
return work(mid, r);
}
signed main() {
n = read(), m = read(), need = read();
for(int i = 1; i <= m; i++){
e[i].u = read() + 1, e[i].v = read() + 1;
e[i].w = read(), e[i].col = read();
}
int k = work(-500, 500);
printf("%lld\n", kruskal(k) - need * k);
return 0;
}