P1026 [NOIP2001 提高组] 统计单词个数

链接:https://www.luogu.com.cn/problem/P1026
题目:

这题的关键点有三个:

①算出来sum[i][j]:原字符串的下标i到j的包含单词总数

②建立dp模型:dp[i][j]表示原字符串以i结尾,分割成j串的结果包含了单词总数。

③给出递推公式:dp[i][j] = dp[l][j-1] + sum[l+1][i]其中l是从j到i - 1的遍历

代码如下:

#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>
typedef long long ll;
using namespace std;
string tar;
vector<string>diction;
int dp[210][50];
int p, k; 
int sum[210][210];
void init()
{
	for (int i = 1; i <= tar.length(); i++)
		for (string u : diction)
			if (tar.substr(i, u.length()) == u )
				sum[i][i + u.length() - 1] = 1;//预处理
	for (int i = 1; i < tar.length(); i++)
		for (int j = i + 1; j < tar.length(); j++)
		{
			sum[i][j] += sum[i][j - 1];
			sum[i][j] = min(1, sum[i][j]);//有一个就足够
		}
	for (int j = 1; j < tar.length(); j++)
		for (int i = j - 1; i > 0; i--)
			sum[i][j] += sum[i+1][j];//sum部分从左到右,从下到上,实现的意义是把原来的含义从i->j是否是字典的内容改为i->j这一块中有几个单词
}
int main()
{
	tar += '0';
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	cin >> p >> k;
	string s;
	for (int i = 1; i <= p; i++) { cin >> s; tar += s; }
	int n; cin >> n;
	for (int i = 0; i < n; i++) { cin >> s; diction.push_back(s); }
	init();
	for (int i = 1; i < tar.length(); i++)dp[i][1] = sum[1][i];
	/*
	for (int j = 1; j <= k; j++)
		for (int i = j; i < tar.length(); i++)
			for (int l = j; l < i; l++)
				dp[i][j] = max(dp[i][j], dp[l][j - 1] + sum[l + 1][i]);
        */
	for (int i = 1; i < tar.length(); i++)
		for (int j = 1; j <= min(k, i); j++)
			for (int l = j; l < i; l++)
				dp[i][j] = max(dp[i][j], dp[l][j - 1] + sum[l + 1][i]);
	cout << dp[tar.length()-1][k];
	return 0;
}

注意其中打了/**/标识的代码块,是下面部分的等效形式,注意l从j开始,到i-1为止

posted on 2024-06-28 14:25  WHUStar  阅读(29)  评论(0编辑  收藏  举报