D. Color with Occurrences

链接

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;
}

posted on 2024-07-20 16:14  WHUStar  阅读(8)  评论(0编辑  收藏  举报