P3025 [USACO11OPEN] Forgotten Password S

比较显然的 DP 是很好思考的。

fif_i 表示前 ii 个字符的答案,转移时枚举 1ji1 \leq j \leq i,判断 jij \sim i 是否是一个单词,如果是,用 fj1+s[ji]f_{j-1}+s[j\cdots i] 转移。

然而我的实现并不太优美,复杂度甚至已经达到了 O(n3m)O(n^3m)。不过其实是跑不满的。因为当 fj1f_{j-1} 为空时,这个转移是不存在的。

这个复杂度其实并不很优,但是题目数据比较弱,所以就可以过了。不过优化也比较容易思考。发现单词长度不超过 2020,所以第二层枚举 jj 只需要 2020 次,就可以达到正确的复杂度了。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <cassert>
using namespace std;

const int N = 1005;

string p[N], s;
string dp[N];
int n, m;

inline string check(string& g)
{
	string res = "-1";
	for (int i = 1; i <= m; i++)
	{
		if (p[i].size() != g.size()) continue;
		bool f = 1;
		for (int j = 0; j < g.size(); j++)
		{
			if (g[j] != '?' && p[i][j] != g[j])
			{
				f = 0;
				break;
			}
		}
		if (f)
		{
			if (res == "-1") res = p[i];
			else res = min(res, p[i]);
		}
	}
	return res;
}

auto main() -> int
{
	ios::sync_with_stdio(0), cin.tie(nullptr), cout.tie(nullptr);
	cin >> n >> m >> s;
	for (int i = 1; i <= m; i++) cin >> p[i];
	for (int i = 0; i < n; i++)
	{
		for (int j = i; j >= 0; j--)
		{
			if (j != 0 && dp[j - 1].empty()) continue;
			string g = s.substr(j, i - j + 1);
			string l = check(g);
			if (l != "-1")
			{
				if (dp[i].empty()) dp[i] = (j == 0 ? "" : dp[j - 1]) + l;
				else dp[i] = min(dp[i], (j == 0 ? "" : dp[j - 1]) + l);
			}
		}
	}
	cout << dp[n - 1] << "\n";
	return 0;
}
posted @   HappyBobb  阅读(4)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示