2026-01-06 hetao1733837 的刷题笔记

2026-01-06 hetao1733837 的刷题笔记

LGP1347 排序

原题链接:排序

分析

虽然......但是......怎么写?

显然套一个数据结构是对的。

等一下,我思考一下如果已经联通......似乎并不见得可以完全确定吧......

居然写过吗?

HT 给了一个极其巧妙的方法:二分答案

观察发现,有解,必然存在某一个点,其之后都有解,二分出来这个点即可。

妙哉妙哉!甚至把拓扑排序隐藏了!

然后 check ⁡ \operatorname{check} check 拿一个传递闭包就行。 n ≤ 30 n\le 30 n≤30,我记得是这样......懒得查了。

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 30;
int n, m;
char c1, c2, c3;
vector<pair<int, int>> e, a;
int d[N][N];
int check(int x){
	memset(d, 0, sizeof(d));
	for (int i = 0; i < x; i++){
		d[e[i].first][e[i].second] = 1;
	}
	for (int k = 1; k <= n; k++){
		for (int i = 1; i <= n; i++){
			for (int j = 1; j <= n; j++){
				d[i][j] |= (d[i][k] & d[k][j]);
			}
		}
	}
	int sum = 0;
	for (int i = 1; i <= n; i++){
		for (int j = 1; j <= n; j++){
			sum += d[i][j];
			if (d[i][j] & d[j][i])
				return 1;
		}
	}
	if (sum == n * (n - 1) / 2)
		return 2;
	return 0;
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> m;
	for (int i = 1; i <= m; i++){
		cin >> c1 >> c2 >> c3;
		e.push_back({c1 - 'A' + 1, c3 - 'A' + 1});	
	}
	int l = 1, r = m;
	while (l <= r){
		int mid = (l + r) >> 1;
		if (check(mid) >= 1)
			r = mid - 1;
		else
			l = mid + 1;
	}
	if (l > m){
		cout << "Sorted sequence cannot be determined.";
		return 0;
	}
	int tmp = check(l);
	if (tmp == 1){
		cout << "Inconsistency found after " << l << " relations.";
		return 0;
	}
	cout << "Sorted sequence determined after " << l << " relations: ";
	for (int i = 1; i <= n; i++){
		int sum = 0;
		for (int j = 1; j <= n; j++){
			sum += d[i][j];
		}
		a.push_back({-sum, i});
	}
	sort(a.begin(), a.end());
	for (auto tmp : a)
		cout << (char)(tmp.second - 1 + 'A');
	cout << ".";
}

发现板子没写......

我到底在干什么?

LGB3644【模板】拓扑排序 / 家谱树

原题链接:【模板】拓扑排序 / 家谱树

分析

很显然吧......按照《算法竞赛》上的 BFS 思路......因为我不会 DFS 求......好像也会吧......

好像 24 年暑假就打这题了......当时没过......

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 105;
int n, a, d[N];
vector<int> e[N];
void topo(){
    queue<int> q;
    for (int i = 1; i <= n; i++){
        if (d[i] == 0){
            cout << i << " ";
            q.push(i);
        }
    }
    while (!q.empty()){
        int u = q.front();
        q.pop();
        for (auto v : e[u]){
            d[v]--;
            if (d[v] == 0){
                cout << v << " ";
                q.push(v);
            }
        }
    }
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n;
    int idx = 1;
    while (idx <= n){
        while (1){
            cin >> a;
            if (a == 0)
                break;
            e[idx].push_back(a);
            d[a]++;
        }
        idx++;
    }
    topo();
}

LGP1685 游览

原题链接:游览

分析

有自环......炸了炸了,没看懂题!

那我走自环岂不是可以无限?

非也非也!这个是说可以组成无向边!

那......感觉上来说就是给定起点和终点求起点到终点的路径数,可能套一个和......

好像会了......吗?

拓扑排序+ DP?还是人类吗?

那就是两个,一个记录路径数量,一个记录花费,最后再加乘船的部分。拓扑排序主要主要是小优化。

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
#define mod 10000
using namespace std;
const int N = 10005;
int n, m, s, t, t0;
vector<pair<int, int>> e[N];
int f[N], g[N]; //分别表示以i为终点的花费和方案数 
int d[N];
void dfs(int u){
	for (auto tmp : e[u]){
		int v = tmp.first, w = tmp.second;
		g[v] = (g[v] + g[u]) % mod;
		f[v] = (f[v] + f[u] + g[u] * w) % mod;
		d[v]--;
		if (!d[v])
			dfs(v);
	}
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> m >> s >> t >> t0;
	for (int i = 1, u, v, w; i <= m; i++){
		cin >> u >> v >> w;
		e[u].push_back({v, w});
		d[v]++;
	}
	g[s] = 1;
	dfs(s);
	cout << ((g[t] - 1) * t0 + f[t]) % mod;
} 

手上起倒刺了,晚上提醒我吃青菜......

LGP3243 [HNOI2015] 菜肴制作

原题链接:[HNOI2015] 菜肴制作

分析

怎么写呢?显然存在一个拓扑序,同时,要求在符合要求的前提下,坏了,语言功能有点小退化......

就是题目那个要求!

注意到这个东西不是完全的字典序,考虑在反图上跑最大,呃......好像就是这么回事,套一个 priority_queue,没了......

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
int T;
int n, m, d[N], topo[N];
vector<int> e[N];
priority_queue<int> q;
int tot;
void toposort(){
	while (!q.empty()){
		q.pop();
	}
	for (int i = 1; i <= n; i++){
		if (d[i] == 0){
			q.push(i);
		}
	}
	while (!q.empty()){
		int u = q.top();
		q.pop();
		topo[++tot] = u;
		for (auto v : e[u]){
			d[v]--;
			if (d[v] == 0){
				q.push(v);
			} 
		}
	}
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> T;
	while (T--){
		for (int i = 1; i <= n; i++){
			e[i].clear();
			d[i] = 0;
			topo[i] = 0;
		}
		tot = 0;
		cin >> n >> m;
		bool flag = true;
		for (int i = 1, u, v; i <= m; i++){
			cin >> u >> v;
			if (u == v)
				flag = false;
			e[v].push_back(u);
			d[u]++;
		}
		if (!flag){
			cout << "Impossible!" << '\n';
			continue;
		}
		toposort();
		if (tot != n){
			cout << "Impossible!" << '\n';
			continue;
		}
		for (int i = tot; i >= 1; i--){
			cout << topo[i] << " ";
		}
		cout << '\n';
	}
}

啥搭配啊?黄绿紫?没有蓝题?

LGP1983 [NOIP 2013 普及组] 车站分级

原题链接:[NOIP 2013 普及组] 车站分级

分析

这个咋建图?

我无法实现建图。

我好像可以实现建图,这个是 O ( n 2 ) O(n^2) O(n2) 的,可以跑下的!就是,我不停的,肯定是小于的对吧!

然后,我不管没有覆盖到的位置,然后呢?

这个是拓扑序的什么?他要求的是最小的划分的级别数。

所以呢?哦,求等级最高的就行。

然后,由于 n ≤ 1 e 3 n\le 1e3 n≤1e3,拿个邻接矩阵反而常数小一点。

那么,要做的就是一层一层剥掉多余的边......我也不太懂......

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int n, m, s, e[N][N];
int topo[N];
int num[N], d[N];
bool vis[N], buc[N];
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> m;
	for (int i = 1; i <= m; i++){
		memset(buc, 0, sizeof(buc));
		cin >> s;
		for (int j = 1; j <= s; j++){
			cin >> num[j];
			buc[num[j]] = 1;
		}
		for (int j = num[1]; j <= num[s]; j++){
			if (!buc[j]){
				for (int k = 1; k <= s; k++){
					if (!e[j][num[k]]){
						e[j][num[k]] = 1;
						d[num[k]]++;
					}
				}
			}
		}
	}
	int top, ans = 0;
	do{
		top = 0;
		for (int i = 1; i <= n; i++){
			if (d[i] == 0 && !vis[i]){
				topo[++top] = i;
				vis[i] = true;
			}
		}
		for (int i = 1; i <= top; i++){
			for (int j = 1; j <= n; j++){
				if (e[topo[i]][j]){
					e[topo[i]][j] = 0;
					d[j]--;
				}
			}
		}
		ans++;
	}while (top);
	cout << ans - 1;
}

显然给放了 O ( n 2 m ) O(n^2m) O(n2m),和我估计的一样......

LGP4934 礼物

原题链接:礼物

分析

真的牛大了,这题直接把拓扑排序引向了处理所有具有大于、小于、大于等于、小于等于关系的问题的解决思路。

数论还在追我/ll

怎么建图?还是 O ( n 2 ) O(n^2) O(n2) 吗?太扯了。

那咋办?瞅一眼题解吧......

好累啊😩好饿啊😣

把事情看作图的点,把先后关系看作有向边,问题转化为图中一个有先后关系的排序,这就是拓扑排序。

对于题目要求 a & b ≥ min ⁡ ( a , b ) a\&b\ge\min(a,b) a&b≥min(a,b),则 a a a 二进制下 1 1 1 所在的数位与 b b b 二进制下 1 1 1 所在的数位存在严格包含关系。

然后,我们设计出一棵决策树来优化建图。

还是不太明白吧......感觉被掏空了......

感觉理解起来还行吧......虽然我不会......

严肃决定明天再写......

2026年1月7日12点57分

论住宿生晚上回家打 CF ⁡ \operatorname{CF} CF 的爽感。

那么,继续。哦,显然可以理解吧......就是说,我们按照发现的那个规律去建图,然后,因为题目很人性地给了一个 k k k,所以,直接枚举所有数,第一层是 0 0 0,第二层是所有 2 2 2 的整数次幂,然后依次增加二进制上 1 1 1 的个数。然后,每一层单开一个盒子,不断继承,似乎没了......

呃......大概就这样吧......我没太看明白他树是在哪,先看代码,写写吧......哦,爽了,下午第一节地理不用去上!

lz 去那外卖,我在机房唱歌好像被听见了,ԾㅂԾ,

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1000005, M = (1 << 20) + 5;
int n, k, a[N], top;
struct node{
	int id, p;
}ans[N];
bool cmp(node x, node y){
	return x.p < y.p;
}
int tot, cnt[M], pre[M], d[M];
bool vis[M], buc[M];
vector<int> e[M];
queue<int> q;
void build(){
	while (!q.empty()){
		q.pop();
	}
	q.push(0);
	while (!q.empty()){
		int u = q.front();
		q.pop();
		for (int i = 0; i < k; i++){
			if (((u >> i) & 1) == 0){
				int v = u | (1 << i);
				e[u].push_back(v);
				d[v]++;
				if (!vis[v]){
					q.push(v);
					vis[v] = 1;
				}
			}
		}
	}
}
void toposort(){
	while (!q.empty()){
		q.pop();
	}
	q.push(0);
	while (!q.empty()){
		int u = q.front();
		q.pop();
		if (buc[u]){
			pre[u]++;
			ans[++top] = {u, pre[u]};
			cnt[pre[u]]++;
		}
		tot = max(tot, pre[u]);
		for (auto v : e[u]){
			d[v]--;
			pre[v] = max(pre[v], pre[u]);
			if (d[v] == 0){
				q.push(v);
			}
		}
	}
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> k;
	for (int i = 1; i <= n; i++){
		cin >> a[i];
		buc[a[i]] = 1;
	}
	build();
	toposort();
	sort(ans + 1, ans + n + 1, cmp);
	cout << 1 << '\n';
	cout << tot << '\n';
	for (int i = 1; i <= n; i++){
		if (ans[i].p != ans[i - 1].p){
			cout << cnt[ans[i].p] << " ";
		}
		cout << ans[i].id << " ";
		if (ans[i].p != ans[i + 1].p){
			cout << '\n';
		}
	}
}
相关推荐
-西门吹雪14 小时前
c++线程之std::async浅析
java·jvm·c++
a努力。14 小时前
国家电网Java面试被问:最小生成树的Kruskal和Prim算法
java·后端·算法·postgresql·面试·linq
王燕龙(大卫)14 小时前
fastdds:DataWriter和DataReader匹配规则
c++
洛生&14 小时前
Counting Towers
算法
CSDN_RTKLIB14 小时前
CMake几个命令顺序
c++
Evand J14 小时前
【MATLAB例程,附代码下载链接】基于累积概率的三维轨迹,概率计算与定位,由轨迹匹配和滤波带来高精度位置,带测试结果演示
开发语言·算法·matlab·csdn·轨迹匹配·候选轨迹·完整代码
X在敲AI代码14 小时前
LeetCode 基础刷题D2
算法·leetcode·职场和发展
qq_3975623114 小时前
昆仑通态屏幕 , 脚本使用笔记
笔记
源代码•宸14 小时前
Leetcode—1929. 数组串联&&Q1. 数组串联【简单】
经验分享·后端·算法·leetcode·go