2026-01-09~12 hetao1733837 的刷题笔记

2026-01-09~12 hetao1733837 的刷题笔记

01-09

孩子们,博主以后不只是 OIer 了,还是 BOer 了!

挺梦幻的,说实话。很早以前我就幻想过双竞甚至多竞,没想到有朝一日真的可能实现!

但是,话又说回来,此时最重要的是低调!太过张扬只会害了你 fbh

刷题!双竞是都要兼顾,为升学提供双重保障,文化课必须不能落!我们也需要给出 BO 生涯的一些规划......同时,我们的 OI 也不是很顶级,所以,必须平衡⚖并最大化收益!

POJ1144 Network

原题链接:Network

分析

割点小板子......

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 105;
int low[N], dfn[N], ncnt;
bool buc[N];
vector<int> e[N];
void dfs(int u, int pre){
	low[u] = dfn[u] = ++ncnt;
	int son = 0;
	for (auto v : e[u]){
		if (!dfn[v]){
			son++;
			dfs(v, u);
			low[u] = min(low[u], low[v]);
			if (low[v] >= dfn[u] && u != 1){
				buc[u] = true;
			}
		}
		else if (dfn[v] < dfn[u] && v != pre){
			low[u] = min(low[u], dfn[v]);
		}
	}
	if (u == 1 && son >= 2)
		buc[1] = true;
}
int n, u, v;
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	while (1){
		scanf("%d", &n);
		if (n == 0){
			return 0;
		}
		memset(low, 0, sizeof(low));
		memset(dfn, 0, sizeof(dfn));
		memset(buc, 0, sizeof(buc));
		ncnt = 0;
		for (int i = 0; i <= n; i++){
			e[i].clear();
		}
		while (scanf("%d", &u) && u){
			while (getchar() != '\n'){
				scanf("%d", &v);
				e[u].push_back(v);
				e[v].push_back(u);
			}
		}
		int ans = 0;
		dfs(1, 1);
		for (int i = 1; i <= n; i++)
			ans += buc[i];
		cout << ans << '\n';
	}
}

01-12

LGP7073 [CSP-J 2020] 表达式

原题链接:[CSP-J 2020] 表达式

分析

对于一个表达式,有些位置对答案是没有贡献的,比如 0 0 0 与某个数按位与, 1 1 1 与某个数按位或,这个数都是没有用的,那么标记一下,先求出整体的答案,然后看有没有被标记即可。

对于非运算,把之后的都取反即可。

表达式用一个栈模拟出来即可。

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1000005; 
string s;
int n, inp[N], q, pos;
int son[N][2];
int buc[N];
int tag[N];
int dfs1(int u, int val){
    inp[u] ^= val;
    if (u <= n) {
        return inp[u];
    }
    int a = dfs1(son[u][0], val ^ buc[son[u][0]]);
    int b = dfs1(son[u][1], val ^ buc[son[u][1]]);
    if (inp[u] == 2){
        if (a == 0){
            tag[son[u][1]] = 1;
        }
        if (b == 0){
            tag[son[u][0]] = 1;
        }
        return a & b;
    } 
    else{
        if (a == 1){
            tag[son[u][1]] = 1;
        }
        if (b == 1){
            tag[son[u][0]] = 1;
        }
        return a | b;
    }
}
void dfs2(int u){
    if (u <= n){
        return ;
    }
    tag[son[u][0]] |= tag[u];
    tag[son[u][1]] |= tag[u];
    dfs2(son[u][0]);
    dfs2(son[u][1]);
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    getline(cin, s);
    cin >> n;
    for (int i = 1; i <= n; i++){
        cin >> inp[i];
    }
    stack<int> stk;
    int cnt = n; 
    for (int i = 0; i < (int)s.length(); i++){
        if (s[i] == ' ') 
            continue; 
        if (s[i] == 'x'){
            int tmp = 0;
            i++;
            while (i < s.length() && s[i] >= '0' && s[i] <= '9'){
                tmp = tmp * 10 + (s[i] - '0');
                i++;
            }
            i--; 
            stk.push(tmp);
        } 
        else if (s[i] == '&'){
            int tmp2 = stk.top(); stk.pop();
            int tmp1 = stk.top(); stk.pop();
            stk.push(++cnt);
            inp[cnt] = 2;
            son[cnt][0] = tmp1;
            son[cnt][1] = tmp2;
        } 
        else if (s[i] == '|'){
            int tmp2 = stk.top(); stk.pop();
            int tmp1 = stk.top(); stk.pop();
            stk.push(++cnt);
            inp[cnt] = 3; 
            son[cnt][0] = tmp1;
            son[cnt][1] = tmp2;
        } 
        else if (s[i] == '!'){
            buc[stk.top()] ^= 1;
        }
    }
    int rt = cnt; 
    int ans = dfs1(rt, buc[rt]);
    dfs2(rt);
    cin >> q;
    while (q--){
        cin >> pos;
        if (tag[pos])
            cout << ans << '\n';
        else
            cout << !ans << '\n';
    }
    return 0;
}

HDU1296 迷宫城堡

原题链接:迷宫城堡

分析

强连通分量......不多说......

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 10005;
vector<int> e[N];
int scc[N], cnt, stk[N], top;
int low[N], dfn[N], ncnt;
void dfs(int u){
	stk[top++] = u;
	low[u] = dfn[u] = ++ncnt;
	for (auto v : e[u]){
		if (!dfn[v]){
			dfs(v);
			low[u] = min(low[u], low[v]);
		}
		else if (!scc[v]){
			low[u] = min(low[u], dfn[v]);
		}
	}
	if (low[u] == dfn[u]){
		cnt++;
		while (true){
			int v = stk[--top];
			scc[v] = cnt;
			if (u == v)
				break;
		}
	}
}
void tarjan(int n){
	cnt = top = ncnt = 0;
	memset(scc, 0, sizeof(scc));
	memset(dfn, 0, sizeof(dfn));
	memset(low, 0, sizeof(low));
	for (int i = 1; i <= n; i++){
		if (!dfn[i])
			dfs(i);
	}
}
int n, m;
signed main(){
	while (scanf("%d %d", &n, &m), n != 0 || m != 0){
		for (int i = 0; i <= n; i++){
			e[i].clear();
		}
		for (int i = 1, u, v; i <= m; i++){
			cin >> u >> v;
			e[u].push_back(v);
		}
		tarjan(n);
		if (cnt == 1)
			cout << "Yes" << '\n';
		else
			cout << "No" << '\n';
	}
}

千万记住,关闭流输入后不要 scanfgetchar 这些东西混用!

LGP2341 [USACO03FALL / HAOI2006] 受欢迎的牛 G

原题链接:[USACO03FALL / HAOI2006] 受欢迎的牛 G

分析

没看懂题解......

那不是要求有且只有一个强连通分量吗?这是对的,那么出度为 0 的点即为明星,这里有且只有一个,如果多个出度为 0 的点,显然不满足。建一个反图更加合适。

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 10005;
int n, m;
vector<int> e[N];
int cnt, low[N], dfn[N], scc[N], sz[N], d[N];
int stk[N], tp, ncnt;
bool vis[N];
void dfs(int u) {
    stk[++tp] = u;
    vis[u] = true;
    low[u] = dfn[u] = ++ncnt;
    for (auto v : e[u]){
        if (!dfn[v]){
            dfs(v);
            low[u] = min(low[u], low[v]);
        } 
        else if (vis[v]){
            low[u] = min(low[u], dfn[v]);
        }
    }
    if (low[u] == dfn[u]){
        cnt++;
        int v;
        do{
            v = stk[tp--];
            vis[v] = false;
            scc[v] = cnt;
            sz[cnt]++;
        }while (u != v);
    }
}
void tarjan(){
    for (int i = 1; i <= n; i++){
        if (!dfn[i]){
            dfs(i);
        }
    }
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> m;
    for (int i = 1, u, v; i <= m; i++){
        cin >> u >> v;
        e[u].push_back(v);
    }
    tarjan();
    for (int u = 1; u <= n; u++){
        for (auto v : e[u]){
            if (scc[u] != scc[v]){
                d[scc[v]]++;
            }
        }
    }
    int dcnt = 0, ans = 0;
    for (int i = 1; i <= cnt; i++){
        if (d[i] == 0){
            dcnt++;
            ans = sz[i];
        }
    }
    if (dcnt == 1){
        cout << ans;
    } 
    else{
        cout << 0;
    }
}

LGP1407 [国家集训队] 稳定婚姻

原题链接:[国家集训队] 稳定婚姻

分析

可不可以理解为,似乎只剩下有向图了......

那咋办啊?和强连通分量的个数关系似乎有一点关系啊。

两个?相当于所有都一样吗?你删了一条边,咋会还一样呢?万一呢?那当我没说好吧......

那么,开始吧......

呃......无向边似乎是为了使得整个图保持联通,怎么搞啊?我好像不太会啊。

正确思路

我们对于夫妻建边,呃......前 npy ⁡ \operatorname{npy} npy 也建边,当一对夫妻在一个环内时,则婚姻不安全。

这个时候可以跑 Tarjan,但是,Tarjan 适用于有向图,所以,建边时要 ⋯ → \dots\rightarrow ⋯→ → \rightarrow → → \rightarrow → → ... \rightarrow\dots →...,这样建边就可以了。

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 20005;
map<string, int> mp;
vector<int> e[N];
int low[N], dfn[N], ncnt, circl[N];
int stk[N], tp, cnt;
bool vis[N];
void dfs(int u){
	low[u] = dfn[u] = ++ncnt;
	stk[++tp] = u;
	vis[u] = true;
	for (auto v : e[u]){
		if (!dfn[v]){
			dfs(v);
			low[u] = min(low[u], low[v]);
		}
		else if (vis[v]){
			low[u] = min(low[u], dfn[v]);
		}
	}
	if (low[u] == dfn[u]){
		cnt++;
		do{
			circl[stk[tp]] = cnt;
			vis[stk[tp]] = 0;
		}while (stk[tp--] != u);
	}
}
void tarjan(int n){
	for (int i = 1; i <= n; i++){
		if (!dfn[i]){
			dfs(i);
		}
	}
}
int n, m;
string g, b;
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n;
	for (int i = 1; i <= n; i++){
		cin >> g >> b;
		mp[g] = i;
		mp[b] = n + i;
		e[i].push_back(n + i);
	}
	cin >> m;
	for (int i = 1; i <= m; i++){
		cin >> g >> b;
		e[mp[b]].push_back(mp[g]);
	}
	tarjan(n * 2);
	for (int i = 1; i <= n; i++){
		if (circl[i] == circl[i + n]){
			cout << "Unsafe" << '\n';
		}
		else{
			cout << "Safe" << '\n';
		}
	}
}

LGP2272 [ZJOI2007] 最大半连通子图

原题链接:[ZJOI2007] 最大半连通子图

分析

妈呀,上题太猎奇了,堪比那个上厕所的......感觉再刷几道可以组一个很猎奇的场了。

感觉这个可以 hxf 容斥......

还是手模样例吧......

强连通显然是极其严格的半联通吧......那我们求出最大的强连通分量之后,直接扩展不就行了?在扩展的过程中似乎可以做......

没模出来......

回去上了一节生竞课,感觉要背的蛮多的......

好的,继续整这道题......我觉得我得做好规划。现在每天的容量相当大啊......
居然是个 DP

记 f f f 为最大半连通子图的大小, g g g 为方案数。在拓扑序上 DP

这里有两个 Trick
1)Tarjan缩点后点的排序是逆拓扑序的
2)拓扑序 DP 下,判断重边只需记录上一个从哪转移即可

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1000005;
int n, m, x;
int low[N], dfn[N], ncnt, belong[N];
vector<int> e[N], g[N];
int f1[N], f2[N];
int stk[N], tp;
bool instk[N];
int cnt;
int sz[N], lst[N];
void dfs(int u){
	low[u] = dfn[u] = ++ncnt;
	stk[++tp] = u;
	instk[u] = true;
	for (auto v : e[u]){
		if (!dfn[v]){
			dfs(v);
			low[u] = min(low[u], low[v]);
		}
		else if (instk[v]){
			low[u] = min(low[u], dfn[v]);
		}
	}
	if (dfn[u] == low[u]){
		cnt++;
		int k;
		do{
			k = stk[tp--];
			belong[k] = cnt;
			sz[cnt]++;
			instk[k] = false;
		}while(k != u);
	}
}
void tarjan(int n){
	for (int i = 1; i <= n; i++){
		if (!dfn[i]){
			dfs(i);
		}
	}
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> m >> x;
	for (int i = 1, u, v; i <= m; i++){
		cin >> u >> v;
		e[u].push_back(v);
	}
	tarjan(n);
	for (int u = 1; u <= n; u++){
		for (auto v : e[u]){
			if (belong[u] == belong[v])
				continue;
			g[belong[u]].push_back(belong[v]);
		}
	}
	for (int i = 1; i <= cnt; i++){
		f1[i] = sz[i]; 
		f2[i] = 1;  
	}
	for (int u = cnt; u >= 1; u--){
		sort(g[u].begin(), g[u].end());
		g[u].erase(unique(g[u].begin(), g[u].end()), g[u].end());
		for (auto v : g[u]){
			if (f1[v] < f1[u] + sz[v]){
				f1[v] = f1[u] + sz[v];
				f2[v] = f2[u];
			}
			else if (f1[v] == f1[u] + sz[v]){
				f2[v] = (f2[v] + f2[u]) % x;
			}
		}
	}
	int maxn = 0, ans = 0;
	for (int i = 1; i <= cnt; i++){
		if (f1[i] > maxn){
			maxn = f1[i];
			ans = f2[i];
		}
		else if (f1[i] == maxn){
			ans = (ans + f2[i]) % x;
		}
	}
	cout << maxn << '\n';
	cout << ans;
	return 0;
}

严肃思考要不要写文化作业......

觉得实在有点学不动了......静下来......那么,让我们进入与 DP 搏斗吧!

相关推荐
fqbqrr2 小时前
2601C++,模块导出分类
前端·c++
say_fall2 小时前
泛型编程基石:C++ 模板从入门到熟练
java·开发语言·c++·编辑器·visual studio
txinyu的博客2 小时前
结合游戏场景解析UDP可靠性问题
java·开发语言·c++·网络协议·游戏·udp
代码游侠2 小时前
学习笔记——嵌入式系统与51单片机核心
笔记·单片机·嵌入式硬件·学习·51单片机
郝学胜-神的一滴2 小时前
深入解析Mipmap层级判定原理:从理论到实践
c++·unity·godot·游戏程序·图形渲染·unreal engine
雾岛听蓝2 小时前
探索C++继承机制
开发语言·c++
过河卒_zh15667662 小时前
情感型AI被“立规矩”,AI陪伴时代进入下半场
人工智能·算法·aigc·生成式人工智能·算法备案
今儿敲了吗2 小时前
计算机网络第三章笔记(四)
笔记·计算机网络
wefg12 小时前
【算法】动态规划
算法·动态规划