1. 程式人生 > 其它 >2021,10,18 題解報告

2021,10,18 題解報告

寫在前面

\(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;
}