专栏文章

题解:P6681 [CCO 2019] Bad Codes

P6681题解参与者 2已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@mimzmltu
此快照首次捕获于
2025/12/01 18:09
3 个月前
此快照最后确认于
2025/12/01 18:09
3 个月前
查看原文
模拟赛 T2,以下为作者的赛时想法。
看到的第一眼估计大部分人觉得是 dp。
首先,考虑一个串串可以记到答案里的条件:
  1. 可以被表示。
  2. 可以有两种不同表示方法。
首先想第二个限制。我们考虑两种表示方法 AABB。他们第一个选的字符串肯定不一样。所以我们枚举第一个选的字符串,这样就只要找到最优的可以把一开始选的两个字符串给填成相同的最小长度。
上面黑色表示一个我们要填平的字符串,而下面的黑色为输入的一个字符串,我们可以用红色的部分后面加一个黑的来填。
我们假设红色为 AA,下面的黑色长度为 lenwlenw,上面的黑色为 BB
那么有:
fB=fA+lenwf_B=f_A+lenw
这个转移是有环的,所以考虑直接跑最短路。
CPP
#include <bits/stdc++.h>
#define int long long 

using namespace std;
const int N = 55;
const int M = 1e6 + 5;
int a[N]; char x[N][N];
int tot;
map <int, int> mp;
struct Edge {
	int v, nxt, w;
} e[M << 1]; int etot, hd[M];
void add_edge(int u, int v, int w) { e[++ etot] = (Edge){v, hd[u], w}; hd[u] = etot; }
int newnode(int x, int len) {
	x += (1ll << len);
	if (mp[x] == 0) mp[x] = ++ tot; 
	return mp[x];
}
struct Node {
	int v, w;
	bool operator > (Node b) const { return w < b.w; }
	bool operator < (Node b) const { return w > b.w; }
};
priority_queue <Node> q;
int dis[M]; bool vis[M]; 
const int inf = 1e9;
void Dis() {
	fill(dis, dis + tot + 1, inf);
	q.push((Node){newnode(0, 0), 0}); dis[newnode(0, 0)] = 0;
	while (!q.empty()) {
		int u = q.top().v; q.pop();
		if (vis[u]) continue; vis[u] = 1;
		for (int i = hd[u] ; i ; i = e[i].nxt) {
			int v = e[i].v; 
			if (dis[v] > dis[u] + e[i].w) {
				dis[v] = dis[u] + e[i].w;
				q.push((Node){v, dis[v]});
			} 
		}
	}
}
signed main() {
	freopen("string.in", "r", stdin);
	freopen("string.out", "w", stdout);
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	int n, m; cin >> n >> m;
	for (int i = 1 ; i <= n ; i ++) {
		cin >> x[i] + 1;
		for (int j = 1 ; j <= strlen(x[i] + 1) ; j ++)
			a[i] = a[i] * 2 + (x[i][j] - '0');
	}
	for (int i = 1 ; i <= n ; i ++) {
		int u = 0;
		for (int j = 1 ; j <= strlen(x[i] + 1) ; j ++) {
			u = u * 2 + (x[i][j] - '0');
			for (int k = 1 ; k <= n ; k ++) {
				int lenk = strlen(x[k] + 1);
				bool flag = 0;
				for (int A = j, B = lenk ; A >= 1 && B >= 1 ; A --, B --) 
					if (x[i][A] != x[k][B]) {
						flag = 1;
						continue;
					} 
				if (flag) continue;
//				cout << i << ' ' << j << ' ' << k << '\n';
				int v = abs(u - a[k]), w = min(j, lenk), len = max(j, lenk);
				v >>= w;
				add_edge(newnode(v, len - w), newnode(u, j), lenk);
			}
		}
	}
	Dis();
	int res = inf;
	for (int i = 1 ; i <= n ; i ++) 
		for (int j = 1 ; j <= n ; j ++)
			if (i != j) { bool flag = 0;
				int leni = strlen(x[i] + 1), lenj = strlen(x[j] + 1);
				for (int A = leni, B = lenj ; A >= 1 && B >= 1 ; A --, B --) {
					if (x[i][A] != x[j][B]) {
						flag = 1;
						break;
					} 
				}
				if (flag) continue;
				int v = abs(a[i] - a[j]); 
				int w = min(leni, lenj), lenv = max(leni, lenj);
				v >>= w; 
				if (dis[newnode(v, lenv - w)] == inf || dis[newnode(v, lenv - w)] == 0) continue;
				res = min(res, dis[newnode(v, lenv - w)] + leni + lenj);
			}
	if (res == inf)  cout << -1;
	else cout << res / 2;
	return 0;
}
/*
4 6
00000
00100
00010
0001
*/
这是考前的题解,所以祝愿大家 NOIP2025 unsigned long long rp = 0; rp --;

评论

1 条评论,欢迎与作者交流。

正在加载评论...