链接
https://codeforces.com/problemset/problem/1714/D
题目
思路
思路1(未实现):首先判断可行性:每个子串都去匹配,然后添加差分数组,对原字符串的每个位置校验,如果每个位置都被覆盖至少一次说明可行;然后再删去最多的线段。思路2(代码中):利用动态规划,借助数组dp[N]表示前i个字符构成的子串最少构建的步数。那么当从状态i-1->i时(就是末尾往后移动一位),就遍历匹配的字符串,如果得到的字符串x能配到后缀相等,那么创建k遍历[i-x.length(),i)
当以k为结尾的子串可以被取到,并且dp[k]+1是∀k∈[i-x.length(),i),dp[k]>-1最小值,那么就令dp[i]=dp[k]+1
。
记录前缀:采用pre[N],上述如果修改了dp[i]则同步修改pre[i]为k,遍历时跳转i=pre[i]
即可
代码
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>
#include<algorithm>
#include<math.h>
#include<sstream>
#include<string>
#include<string.h>
#include<iomanip>
#include<stdlib.h>
#include<map>
#include<queue>
#include<limits.h>
#include<climits>
#include<fstream>
#include<stack>
#define IOS ios::sync_with_stdio(false), cin.tie(0) ,cout.tie(0)
using namespace std;
#define int long long
const int L = 110;
int dp[L], pre[L], usid[L];
signed main()
{
IOS;
int q; cin >> q;
while (q--)
{
string t; cin >> t;
t = '0' + t;
int n; cin >> n;
vector<string>ss;
memset(dp, 0, sizeof(dp));
memset(pre, 0, sizeof(pre));
memset(usid, 0, sizeof(usid));
for (int i = 1; i <= n; i++) { string s; cin >> s; ss.push_back(s); }
for (int i = 1; i < t.length(); i++)
{
for (int j = 0; j < ss.size(); j++)
{
string now = ss[j];
if (i < now.length())continue;
if (t.substr(i - now.length() + 1, now.length()) == now)
{
for (int k = i - now.length(); k < i; k++)
{
if (dp[k] == -1)continue;
if (dp[i] == 0 or dp[i] > dp[k] + 1)
{
dp[i] = dp[k] + 1;
pre[i] = k;
usid[i] = j;
}
}
}
}
if (dp[i] == 0)dp[i] = -1;
}
if (dp[t.length() - 1] != -1)
{
cout << dp[t.length() - 1] << '\n';
int now = t.length() - 1;
while (now)
{
cout << usid[now] + 1 << ' ' << now - ss[usid[now]].length() + 1<<'\n';
now = pre[now];
}
}
else cout << -1<<'\n';
}
return 0;
}
标签:pre,now,Color,int,length,Occurrences,include,dp
From: https://www.cnblogs.com/zzzsacmblog/p/18313284