题解:P11202 [JOIG 2024] 名前 / Name
Fated_Shadow · · 题解
前言
看了下题解区,全是 bfs 写法,所以专门搓了一篇 dp 来补一下。
思路
发现去掉
现在考虑哪些状态可以优化掉。由于
那么这
为了方便,可以直接使用 4 进制的状压,直接进行滚动即可。
最后再处理一下往当前结尾的状态里面塞集合外的字母的最小值即可,时空复杂
Code
Talk is cheap, show me the code.
// Problem: P11202 [JOIG 2024] 名前 / Name
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P11202
// Memory Limit: 1 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
#define int long long
using namespace std;
namespace FastIO {
char gc() {
static char buf[1 << 24], *is = buf, *it = buf;
if (is == it) is = buf, it = is + fread(buf, 1, 1 << 24, stdin);
return is == it ? EOF : *is ++;
}
char out[1 << 24];
int len;
void flush() { fwrite(out, 1, len, stdout), len = 0; }
void pc(char x) {if (len == 1 << 24) flush(); out[len ++] = x;}
struct Flusher {~Flusher() {flush();} } Fls;
// #define gc() getchar()
// #define pc(X) putchar(X)
inline void read(char& ch) {ch = gc();}
inline void read(char *s) {
char ch = gc();
while (ch < 33 || ch > 126) ch = gc();
for (; ch >= 33 && ch <= 126; ch = gc()) *s++ = ch;
*s = '\0';
}
template <class T>
inline void read(T &x) {
char c, flag = 0;
while ((c = gc()) < '0' || c > '9') flag |= c == '-';
x = c & 15;
while ((c = gc()) >= '0' && c <= '9')
x = (x << 3) + (x << 1) + (c & 15);
if (flag) x = ~x + 1;
}
template <class T, class ...T1>
inline void read(T &x, T1 &...x1) {read(x), read(x1...);}
template <class T>
inline void _put(T x) {if(x > 9) _put(x / 10); pc((x % 10) | 48);}
template <class T>
inline void write(T x) {if(x < 0) pc('-'), x = ~x + 1; _put(x);}
template <> inline void write(char x) {pc(x);}
template <class T, class ...T1>
inline void write(T x, T1 ...x1) {write(x), write(x1...);}
}
using FastIO::read;
using FastIO::write;
template <class T>
inline bool chkmin(T &x, T y) {return x > y ? x = y, 1 : 0;}
template <class T>
inline bool chkmax(T &x, T y) {return x < y ? x = y, 1 : 0;}
const int N = 5e2 + 10, M = 1 << 6;
int n, m, k, dp[N][N][M], ans, lim;
char s[N], t[N];
bool check(int i, int j, int sta, int f1, int f2) {
int cs = 0, ct = 0, flag = 0;
while(sta) cs += sta & 3 & 1, ct += (sta & 3 & 2) >> 1, sta >>= 2;
if(f1) for(int p = 1; p <= cs && p < i; ++p) flag |= (s[i] == s[i - p]);
if(f1) for(int p = 1; p <= ct && j - p - f2 + 1 > 0; ++p)
flag |= (s[i] == t[j - p - f2 + 1]);
if(f2) for(int p = 1; p <= ct && p < j; ++p) flag |= (t[j] == t[j - p]);
if(f2) for(int p = 1; p <= cs && i - p - f1 + 1 > 0; ++p)
flag |= (t[j] == s[i - p - f1 + 1]);
return !flag;
}
void solve(int i, int j, int f1, int f2) {
int now = f1 * 1 + f2 * 2;
for(int sta = 0; sta <= lim; ++sta) if(check(i, j, sta, f1, f2))
chkmin(dp[i][j][((sta << 2) + now) & lim], dp[i - f1][j - f2][sta] + 1);
for(int sta = lim; ~sta; --sta) for(int p = 1; p <= k; ++p)
chkmin(dp[i][j][(sta << (p * 2)) & lim], dp[i][j][sta] + p);
}
signed main() {
// freopen(".in", "r", stdin);
// freopen(".out", "w", stdout);
read(n, m, k), read(s + 1), read(t + 1); memset(dp, 0x3f, sizeof dp);
dp[0][0][0] = 0, ans = (n + m) * (k + 1), lim = (1 << (2 * k)) - 1;
for(int i = 0; i <= n; ++i)
for(int j = 0; j <= m; ++j) {
if(i && j && s[i] == t[j]) solve(i, j, 1, 1);
if(i) solve(i, j, 1, 0);
if(j) solve(i, j, 0, 1);
}
for(int sta = 0; sta <= lim; ++sta) chkmin(ans, dp[n][m][sta]);
write(ans);
return 0;
}
End
如有问题,欢迎指正。