2025-11-13~14 hetao1733837的刷题记录

2025-11-13~14 hetao1733837的刷题记录

11-13

[JOISC 2014]Water Bottle

原题链接1:[P14422 [JOISC 2014] 水桶 / Water Bottle]([P14422 JOISC 2014] 水桶 / Water Bottle - 洛谷)

原题链接2:#2876. 「JOISC 2014 Day2」水壶

洛谷题名怎么和LOJ不一样啊/(ㄒoㄒ)/~~

分析

呃,不知从哪冒出了瓶颈最短路 这个词,被mhh认为是正确的,因此引发了瓶颈生成树(整张图),因为由定义"无向图 G G G的瓶颈生成树是这样的一个生成树,它的最大的边权值在 G G G的所有生成树中最小。"而瓶颈生成树又是最小生成树,所以转化为原图求最小生成树,两点之间距离转化为树上路径,可以直接建 K r u s k a l Kruskal Kruskal重构树(最小生成树多维护一下最大两点距离而已)跑倍增,斜二倍增甚至树剖都可以。但是问题在于 O ( n 2 ) O(n^{2}) O(n2)建图是无法接受的,因为原图是个矩阵......线段树优化建图,?可行但是吃多了。看一眼 t a g tag tag,惊奇发现 b f s bfs bfs,容我稍考......多源 b f s bfs bfs即可?好吧,我基础是一坨......

那么,就可以写代码了?我真是吃多了......

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int HW = 2005, P = 400005;
char c[HW][HW];
pair<int, int> vis[HW][HW];
struct node{
	int a, b;
}inp[P];
int h, w, p, q;
int dx[] = {1, 0, -1, 0},
	dy[] = {0, -1, 0, 1};
int fa[P * 2]; 
int getfa(int x){
	return x == fa[x] ? x : fa[x] = getfa(fa[x]);
}
struct node1{
	int u, v, w;
}e[HW * HW];
bool cmp(node1 o1, node1 o2){
	return o1.w < o2.w;
}
vector<int> g[P * 2]; 
int we[P * 2], de[P * 2]; 
pair<int, int> f[P * 2][21]; 
void dfs(int u){
	for (int i = 1; i <= 20; i++){
		f[u][i].first = f[f[u][i - 1].first][i - 1].first;
		f[u][i].second = max(f[u][i - 1].second, f[f[u][i - 1].first][i - 1].second);
	}
	for (auto v : g[u]){
		f[v][0].first = u;
		f[v][0].second = we[v];
		de[v] = de[u] + 1;
		dfs(v);
	}
	return ;
}
int ans;
void lca(int x, int y){
	ans = 0;
	if (de[x] < de[y])
		swap(x, y);
	for (int i = 20; i >= 0; i--){
		if (de[f[x][i].first] >= de[y]){
			ans = max(ans, f[x][i].second);
			x = f[x][i].first;
		}
	} 
	if (x == y){
		return ;
	}
	else{
		for (int i = 20; i >= 0; i--){
			if (f[x][i].first != f[y][i].first){
				ans = max(ans, f[x][i].second);
				ans = max(ans, f[y][i].second);
				x = f[x][i].first;
				y = f[y][i].first;
			}
		}
		ans = max(ans, we[x]);
		ans = max(ans, we[y]);
		ans = max(ans, we[f[x][0].first]);
	}
	return ;
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	//input
	cin >> h >> w >> p >> q;
	for (int i = 1; i <= h; i++){
		string s;
		cin >> s;
		for (int j = 0; j < w; j++){
			c[i][j + 1] = s[j];
		}
	}
	for (int i = 1; i <= h; i++){
		for (int j = 1; j <= w; j++){
			vis[i][j] = {0, 0};
		}
	}
	queue<pair<int, int>> qu;
	for (int i = 1; i <= p; i++){
		cin >> inp[i].a >> inp[i].b;
		vis[inp[i].a][inp[i].b] = {0, i};
		qu.push({inp[i].a, inp[i].b});
	}
	//bfs
	int top = 0;
	while (!qu.empty()){
		int x = qu.front().first;
		int y = qu.front().second;
		qu.pop();
		for (int i = 0; i < 4; i++){
			int tx = x + dx[i], ty = y + dy[i];
			if (tx >= 1 && tx <= h && ty >= 1 && ty <= w && c[tx][ty] == '.'){
				if (!vis[tx][ty].second){
					vis[tx][ty] = {vis[x][y].first + 1, vis[x][y].second};
					qu.push({tx, ty});
				}
				else if (vis[x][y].second != vis[tx][ty].second){
					e[++top] = {vis[x][y].second, vis[tx][ty].second, vis[x][y].first + vis[tx][ty].first};
				}
			}
		}
	}
	//Kruskal
	for (int i = 1; i < p; i++)
		e[++top] = {i, i + 1, 0x3f3f3f3f3f3f3f3f};
	sort(e + 1, e + top + 1, cmp);
	int cur = p;
	for (int i = 1; i <= p * 2; i++)
		fa[i] = i;
	for (int i = 1; i <= top; i++){
		int x = e[i].u, y = e[i].v, z = e[i].w;
		int fx = getfa(x), fy = getfa(y);
		if (fx == fy)
			continue;
		cur++;
		g[cur].push_back(fx);
		g[cur].push_back(fy);
		fa[fx] = fa[fy] = cur; 
		we[cur] = z;
	}
	for (int i = 1; i <= cur; i++){
		for (int j = 0; j <= 20; j++){
			f[i][j] = {0, 0};
		}
	}
	de[cur] = 1;
	f[cur][0] = {cur, we[cur]};
	dfs(cur);
	//solve
	while (q--){
		int x, y;
		cin >> x >> y;
		if (x == y){
			cout << 0 << '\n';
			continue;
		}
		ans = 0;
		lca(x, y);
		if (ans == 0x3f3f3f3f3f3f3f3f)
			cout << -1 << '\n';
		else
			cout << ans << '\n';
	}
	return 0;
}

吃饱了......

[JOISC 2014] Making Friends is Fun

原题链接1:[JOISC 2014] 有趣的交朋友 / Making Friends is Fun

原题链接2:「JOISC 2014 Day2」交朋友

分析

利用人类智慧一下就模拟出来了,哈哈哈哈哈哈哈哈哈......计算机,靠你了......靠不住/(ㄒoㄒ)/~~

像这样一个点指向两外两个点,有点像树啊......加上边像基环树?我在胡言乱语......问一下...... t a g tag tag里给出了并查集,给我一些恍惚的启发......难道就是这样的"有向三角"?Oh,我有了一些思路,额外记录每个点的入度和出度,然后对于没有入度的点,对其出度进行排列组合,呃,好像还要做一些去重,这些是 t a g tag tag里的 b f s bfs bfs吗?我需要询问。

呃,花花的思路大概是打标记打标记,然后啊吧啊吧啊吧啊,我也并非深刻理解。

但是,aoao的很具启发性,是一种很数学的做法,类似排列组合,虽然并未理解精髓。

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 100005;
int n, m, a, b;
vector<int> e[N];
int fa[N], sz[N];
int getfa(int x){
    return x == fa[x] ? fa[x] : fa[x] = getfa(fa[x]);
}
void merge(int x, int y){
    x = getfa(x);
    y = getfa(y);
    if (x != y){
        if (sz[x] > sz[y])
            swap(x, y);
        fa[x] = y;
        sz[y] += sz[x];
    }
}
void dfs(int u){
    for (auto v : e[u]){
        if (getfa(u) == getfa(v))
            continue;
        merge(u, v);
        dfs(v);
    }
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> m;
    for (int i = 1; i <= m; i++){
        cin >> a >> b;
        e[a].push_back(b);
    }
    for (int i = 1; i <= n; i++){
        fa[i] = i;
        sz[i] = 1;
    }
    for (int i = 1; i <= n; i++){
        int tmp = 0;
        for (auto v : e[i]){
            if (!tmp){
                tmp = v;
                continue;
            }
            merge(tmp, v);
            tmp = v;
        }
    }
    for (int i = 1; i <= n; i++)
        if (sz[getfa(i)] >= 2)
            dfs(i);
    int ans = 0;
    for (int i = 1; i <= n; i++){
        if (getfa(i) == i)
            ans += sz[i] * (sz[i] - 1);
        for (auto v : e[i]){
            if (getfa(v) == getfa(i)){
                continue;
            }
            ans++;
        }
    }
    cout << ans;
}

花花思路也很巧妙!对于两个点,如果连了双向边,那么就可以直接合并它们的儿子,对于一些还没有合并儿子的,直接合并然后递归儿子即可,那么打一下标记即可。代码我会(will)写吗?

11-14

[CSP-S 2023] 结构体

原题链接:[CSP-S 2023] 结构体

分析

吃饭前写了 o p = = 1 op==1 op==1和 o p = = 2 op==2 op==2两个,交了一发全WA了。

16 : 20 {\color{Black}{16:20}} 16:20 不会后两个,感觉要额外记录,初觉不对。决定找AI把前两个修一下,瞅一眼题解。

16 : 35 {\color{Black}{16:35}} 16:35 吃不动了,决定he题解。发现有一篇思路十分接近。

wcnm,为啥题解是错的!!!

™不写了。

[CSP-S 2025] 道路修复 / road

原题链接:[CSP-S 2025] 道路修复 / road

分析

考场上在仅剩的40分钟里想到了最小生成树,结果,忘了板子,以为赛季结束了/(ㄒoㄒ)/~~

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 2000005, M = 10000005;
int n, m, k;
int fa[N];
struct node{
    int u, v, w;
}e[M], g[N];
int c[N];
bool vis[N];
bool cmp(node x, node y){
    return x.w < y.w;
}
int getfa(int x){
    return fa[x] == x ? x : fa[x] = getfa(fa[x]);
}
int main(){
    cin >> n >> m >> k;
    for (int i = 1; i <= m; i++){
        cin >> e[i].u >> e[i].v >> e[i].w;
    } 
    sort(e + 1, e + m + 1, cmp);
    for (int i = 1; i <= n; i++)
        fa[i] = i;
    int cnt = 0;
    for (int i = 1; i <= m; i++){
        int fu = getfa(e[i].u), fv = getfa(e[i].v);
        if (fu == fv) 
            continue;
        fa[fu] = fv;
        g[++cnt] = e[i];
        if (cnt == n - 1) 
            break;
    }
    cnt = m;
    for (int i = 1; i <= k; i++){
        cin >> c[i];
        for (int j = 1; j <= n; j++){
            cnt++;
            e[cnt].u = j;
            e[cnt].v = n + i;
            cin >> e[cnt].w;
        }
    }
    sort(e + 1, e + cnt + 1, cmp);
    long long ans = 0x3f3f3f3f3f3f3f3f;
    for (int mask = 0; mask < (1 << k); mask++){
        long long cur = 0;
        int num = 0;
        for (int j = 0; j < k; j++){
            if (mask >> j & 1){
                num++;
                cur += c[j + 1];
            }
        }
        for (int i = 1; i <= n + k; i++)
            fa[i] = i;
        int need = n + num - 1;
        for (int i = 1; i <= cnt; i++){
            int u = e[i].u, v = e[i].v;
            if (v > n) {
                int id = v - n;
                if (!(mask >> (id - 1) & 1)) 
                    continue;
            }
            int fu = getfa(u), fv = getfa(v);
            if (fu == fv) 
                continue;
            fa[fu] = fv;
            cur += e[i].w;
            need--;
            if (need == 0) 
                break;
        }
        if (need == 0)
            ans = min(ans, cur);
    }
    cout << ans;
    return 0;
}

两遍 K r u s k a l Kruskal Kruskal,行吧......我是sugar 这启示我们, 多重限制,时间复杂度允许,就多跑几层,分层的思想还是很常用的。 \color{Black}{多重限制,时间复杂度允许,就多跑几层,分层的思想还是很常用的。} 多重限制,时间复杂度允许,就多跑几层,分层的思想还是很常用的。

好吧,要去听烫烫选科讲座了,我不明白,竞赛班不是选物化生吗?反正我是这么打算的。毕竟文科从开学以来没咋听过(●'◡'●)

OSU!

原题链接:OSU!

分析

维护 x 1 x1 x1表示 x x x的期望, x 2 x2 x2表示 x 2 x^2 x2的期望。

x 1 i = ( x 1 i − 1 + 1 ) × p i x1_i=(x1_{i-1}+1)\times p_i x1i=(x1i−1+1)×pi

x 2 i = ( x 2 i − 1 + 2 × x 1 i − 1 + 1 ) × p i x2_i=(x2_{i-1}+2\times x1_{i - 1} + 1)\times p_i x2i=(x2i−1+2×x1i−1+1)×pi

a n s i = a n s i − 1 + ( 3 × x 2 i − 1 + 3 × x 1 i − 1 + 1 ) × p i ans_i=ans_{i-1}+(3 \times x2_{i - 1}+ 3 \times x1_{i-1} + 1) \times p_i ansi=ansi−1+(3×x2i−1+3×x1i−1+1)×pi

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
int n;
double x1[N], x2[N], ans[N], p[N];
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n;
    for (int i = 1; i <= n; i++){
        cin >> p[i];
    }
    for (int i = 1; i <= n; i++){
        x1[i] = (x1[i - 1] + 1) * p[i];
        x2[i] = (x2[i - 1] + 2 * x1[i - 1] + 1) * p[i];
        ans[i] = ans[i - 1] + (3 * x2[i - 1] + 3 * x1[i - 1] + 1) * p[i];
    }
    cout << fixed << setprecision(1) << ans[n];
}

[JXOI2018] 游戏

原题链接:[JXOI2018]游戏

分析

设有 k k k个关键点,把序列分成 k + 1 k+1 k+1段。对于每个非关键点,排在关键点后面概率为 P = 1 k + 1 P=\frac{1}{k+1} P=k+11,期望 E = ( n − k ) P = n − k k + 1 E=(n-k)P=\frac{n-k}{k+1} E=(n−k)P=k+1n−k,最后一个关键点期望 E n = k ( n + 1 ) k + 1 E_n=\frac{k(n+1)}{k+1} En=k+1k(n+1),最终答案 k k + 1 ( n + 1 ) ! \frac{k}{k+1}(n+1)! k+1k(n+1)!。

正解

cpp 复制代码
#include <bits/stdc++.h>
#define mod 1000000007
#define int long long
using namespace std;
const int N = 10000005;
int l, r;
bool vis[N];
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> l >> r;
    int k = 0;
    for (int i = l; i <= r; i++){
        if (!vis[i]){
            k++;
            for (int j = i * 2; j <= r; j += i){
                vis[j] = 1;
            }
        }
    }
    int ans = k;
    for (int i = 1; i <= r - l + 2; i++){
        if (i != k + 1)
            ans = ans * i % mod;
    }
    cout << ans;
}
相关推荐
hansang_IR2 小时前
【题解】洛谷 P2476 [SCOI2008] 着色方案 [记搜]
c++·算法·记忆化搜索
趙卋傑2 小时前
常见排序算法
java·算法·排序算法
AA陈超3 小时前
ASC学习笔记0010:效果被应用时的委托
c++·笔记·学习
AA陈超3 小时前
ASC学习笔记0004:通知相关方能力规格已被修改
c++·笔记·学习·游戏·ue5·游戏引擎·虚幻
阿巴~阿巴~3 小时前
IPv4地址转换函数详解及C++容器安全删除操作指南
linux·服务器·c++·网络协议·算法·c++容器安全删除操作·ipv4地址转换函数
TT哇3 小时前
【面经 每日一题】面试题16.25.LRU缓存(medium)
java·算法·缓存·面试
oioihoii3 小时前
C/C++混合项目中的头文件管理:.h与.hpp的分工与协作
java·c语言·c++
SKYDROID云卓小助手3 小时前
无人设备遥控器之差分信号抗干扰技术
网络·stm32·单片机·嵌入式硬件·算法
美狐美颜SDK开放平台3 小时前
什么是美颜sdk?美型功能开发与用户体验优化实战
人工智能·算法·ux·直播美颜sdk·第三方美颜sdk·视频美颜sdk