题解:P6681 [CCO 2019] Bad Codes
Identity_Equation · · 题解
模拟赛 T2,以下为作者的赛时想法。
看到的第一眼估计大部分人觉得是 dp。
首先,考虑一个串串可以记到答案里的条件:
-
可以被表示。
-
可以有两种不同表示方法。
首先想第二个限制。我们考虑两种表示方法
上面黑色表示一个我们要填平的字符串,而下面的黑色为输入的一个字符串,我们可以用红色的部分后面加一个黑的来填。
我们假设红色为
那么有:
这个转移是有环的,所以考虑直接跑最短路。
#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 --;