EOJ 3261 分词

Posted Fighting Heart

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了EOJ 3261 分词相关的知识,希望对你有一定的参考价值。

字典树,$dp$。

记录$dp[i]$为以$i$为结尾获得的最大价值。枚举结尾一段是哪个单词,更新最大值。可以将字典中单词倒着建一棵字典树。

这题数据有点不严谨。

下面这组数据答案应该是负的。

3

a 0.1

aa 0.1

aaa 0.1

1

aaa

下面这组数据没通过的代码在$OJ$上也可以$AC$......

3

a 2

aa 2

aaa 2

1

aaab

正确答案是:

6.238325

aaa b

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

double eps = 1e-7;

struct X
{
	double f;
	int nx[26];
}s[300010];
int sz=0,root=0;

int n,T;
char t[5010];
char tt[5010];
double w;

double dp[5010];
int pre[5010];

int r[5010];

void Insert()
{
	int p = root;
	int len = strlen(t);
	for(int i=len-1 ; i>=0 ;i--)
	{
		if(t[i]>=‘A‘&&t[i]<=‘Z‘) t[i] = t[i] -‘A‘ + ‘a‘;
		if(s[p].nx[t[i]-‘a‘]==-1) s[p].nx[t[i]-‘a‘] = ++sz;
		p = s[p].nx[t[i]-‘a‘];
	}
	s[p].f = w;
}

double get(int x)
{
	if(x<0) return 0.0;
	return dp[x];
}

double work(double x)
{
	if(x==0.0) return 0.0;
	return log(x);
}

int main()
{
	scanf("%d",&n);

	for(int i=0;i<=300005;i++)
	{
		s[i].f = 0;
		for(int j=0;j<=25;j++) s[i].nx[j] = -1;
	}
	
	sz=0;


	for(int i=1;i<=n;i++)
	{
		scanf("%s%lf",t,&w);
		Insert();
	}

	scanf("%d",&T);
	while(T--)
	{
		scanf("%s",t); tt[0]=0; strcpy(tt,t);
		int len = strlen(t);

		for(int i=0;i<len;i++) 
		{
			if(t[i]>=‘A‘&&t[i]<=‘Z‘)
				t[i] = t[i] - ‘A‘ +‘a‘;
		}

		memset(dp,0,sizeof dp);
		memset(pre,-1,sizeof pre);

		for(int i=0;i<len;i++)
		{
			int now = i, p = root;

			while(1)
			{
				if(now<0) break;
				if(s[p].nx[t[now]-‘a‘]==-1) 
				{
					for(int e=0;e<now;e++)
					{
						if(dp[i] < dp[e])
						{
							dp[i] = dp[e];
							pre[i] = e;
						}
					}
					break;
				}
				p = s[p].nx[t[now]-‘a‘];

				if(get(now-1) + work(s[p].f)*(i-now+1)*(i-now+1) > dp[i])
				{
					dp[i] = get(now-1) + work(s[p].f)*(i-now+1)*(i-now+1);
					pre[i] = now-1;
				}
				
				now--;
			}
		}

		printf("%.6f\n",dp[len-1]);

		memset(r,0,sizeof r);

		int pp = pre[len-1];

		while(1)
		{
			if(pp<0) break;
			r[pp]=1;
			pp = pre[pp];
		}

		for(int i=0;i<len;i++)
		{
			printf("%c",tt[i]);
			if(r[i]) printf(" ");
		}
		printf("\n");

	}

	return 0;
}

以上是关于EOJ 3261 分词的主要内容,如果未能解决你的问题,请参考以下文章

EOJ_3653. 她的名字 预处理 组合数

POJ 3261 Milk Patterns(后缀数组+二分答案)

Javalucene4.0学习心得

EOJ Monthly 2018.2 (Good bye 2017)

POJ-3261 Milk Patterns(后缀数组)

[洛谷P3261] [JLOI2015]城池攻占(左偏树)