HDU 2296

很明显的DP状态了,设dp[i][j],设当前在状态点i,经过j步能得到的最大分值。也是从root直接扩展就可以了。

至于字符串,实在有点困难,开始想着记录路径,但后来发现路径从后往前回溯不一定是字典序最小,夭折。。。看别人的,发现直接就把字符串存下来,跪了,也对,毕竟才50个。

直接存字符串,比较,选最小,即可。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits>
#include <string.h>
#include <queue>
#include <cmath>
#include <map>
#include <vector>
#define LL  __int64
using namespace std;

const int Maxn=1110;
const int dictsize=26;
const int root=0;
const int inf=(1<<30);
int fail[Maxn],trie[Maxn][dictsize];
int hv[Maxn];
int tag[Maxn];
int head,tail,tot;
int que[Maxn];
char str[Maxn];
int n,m,anshv;
int dp[Maxn][55];
char dpc[Maxn][55][55];
char ans[55];

void Insert_trie(int s){
	int p=0,i=0,index;
	while(str[i]){
		index=str[i]-‘a‘;
		if(trie[p][index]==-1) trie[p][index]=++tot;
		p=trie[p][index];
		i++;
	}
	tag[p]=s;
}

void build_ac(){
	head=tail=0;
	que[tail++]=root;
	while(head!=tail){
		int tmp=que[head++];
		int p=-1;
		for(int i=0;i<dictsize;i++){
			if(trie[tmp][i]!=-1){
				if(tmp==root) fail[trie[tmp][i]]=root;
				else{
					p=fail[tmp];
					while(p!=-1){
						if(trie[p][i]!=-1){
							fail[trie[tmp][i]]=trie[p][i];
							break;
						}
						p=fail[p];
					}
					if(p==-1) fail[trie[tmp][i]]=root;
				}
				if(tag[fail[trie[tmp][i]]]>=0) tag[trie[tmp][i]]=tag[fail[trie[tmp][i]]];
				que[tail++]=trie[tmp][i];
			}
			else{	//trie[tmp][i]==-1
				if(tmp==root) trie[tmp][i]=root;
				else{
					p=fail[tmp];
					while(p!=-1){
						if(trie[p][i]!=-1){
							trie[tmp][i]=trie[p][i];
							break;
						}
						p=fail[p];
					}
					if(p==-1) trie[tmp][i]=root;
				}
			}
		}
	}
}

bool cmp(char s1[],char s2[])
{
    int len1=strlen(s1);
    int len2=strlen(s2);
    if(len1 != len2)return len1 < len2;
    else return strcmp(s1,s2) < 0;
}

int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&m);
		head=tail=tot=0;
		memset(fail,-1,sizeof(fail));
		memset(trie,-1,sizeof(trie));
		memset(tag,-1,sizeof(tag));
		for(int i=0;i<m;i++){
			scanf("%s",str);
			Insert_trie(i);
		}
		for(int i=0;i<m;i++)
		scanf("%d",&hv[i]);
		build_ac();
	//	cout<<"YES"<<endl;
		for(int i=0;i<=tot;i++){
			for(int j=0;j<=n;j++){
				strcpy(dpc[i][j],"");
				dp[i][j]=-1;
			}
		}
		dp[0][0]=0;
		strcpy(ans,"");
		anshv=0;
		for(int j=0;j<n;j++){
			for(int i=0;i<=tot;i++){
				if(dp[i][j]>=0){
					strcpy(str,dpc[i][j]);
					int len=strlen(str);
					for(int k=0;k<dictsize;k++){
						int son=trie[i][k];
						str[len]=‘a‘+k;
						str[len+1]=‘\0‘;
						int tt=dp[i][j];
						if(tag[son]>=0)
						tt+=hv[tag[son]];
						if(dp[son][j+1]<tt||(tt==dp[son][j+1]&&cmp(str,dpc[son][j+1]))){
							dp[son][j+1]=tt;
							strcpy(dpc[son][j+1],str);
						}
						if(dp[son][j+1]>anshv||dp[son][j+1]==anshv&&cmp(dpc[son][j+1],ans)){
							anshv=dp[son][j+1];
							strcpy(ans,dpc[son][j+1]);
						}
					}
				}
			}
		}
		puts(ans);
	}
	return 0;
}

  

时间: 2024-12-13 21:59:06

HDU 2296的相关文章

hdu 2296 aC自动机+dp(得到价值最大的字符串)

Ring Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3180    Accepted Submission(s): 1033 Problem Description For the hope of a forever love, Steven is planning to send a ring to Jane with a rom

HDU 2296 Ring

Ring Time Limit: 1000ms Memory Limit: 32768KB This problem will be judged on HDU. Original ID: 229664-bit integer IO format: %I64d      Java class name: Main For the hope of a forever love, Steven is planning to send a ring to Jane with a romantic st

HDU 2296 Ring [AC自动机 DP 打印方案]

Ring Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3536 Accepted Submission(s): 1153 Problem Description For the hope of a forever love, Steven is planning to send a ring to Jane with a romantic

HDU 2296 Ring AC自动机 + DP

题意:给你n个模式串,每个模式串有一个得分,让你构造出一个长度为N之内且分数最高的文本串;输出字典序列最小的. 解题思路:  AC自动机 + DP , 不过要输出字典序列最小,多开一个 一个三维字符串来辅助二维DP(新思路) , DP[i][j] ,表示到i位置状态为j的最大得分. 解题代码: 1 // File Name: temp.cpp 2 // Author: darkdream 3 // Created Time: 2014年09月11日 星期四 15时18分4秒 4 5 #inclu

HDU 2296 Ring (AC自动机 + DP)

题目链接:Ring 解析:m个有价值的串,字符串s在字符串str中的价值 = s在str中出现的次数 × s的价值.问价值最大的长度为n的串是什么. 本题需要输出字典序最小的 在DP的时候开一个数组记录结果即可. AC代码: #include <algorithm> #include <iostream> #include <cstdio> #include <queue> #include <cstring> using namespace s

AC自动机

AC自动机 直接学AC自动机比较难理解,强烈建议先学完KMP和字典树并进行一定的练习后,对于失配指针和字典树构造有一定理解后再来学AC自动机的内容.有关AC自动机的详细介绍可见刘汝佳的<算法竞赛入门经典训练指南>P214. 给你一个字典(包含n个不重复的单词),然后给你一串连续的字符串文本(长为len),问你该文本里面的哪些位置正好出现了字典中的某一个或某几个单词?输出这些位置以及出现的单词. 这个问题可以用n个单词的n次KMP算法来做(效率为O(n*len*单词平均长度)),也可以用1个字典

转自kuangbin的AC自动机(赛前最后一博)

有了KMP和Trie的基础,就可以学习神奇的AC自动机了.AC自动机其实就是在Trie树上实现KMP,可以完成多模式串的匹配.           AC自动机 其实 就是创建了一个状态的转移图,思想很重要.           推荐的学习链接: http://acm.uestc.edu.cn/bbs/read.php?tid=4294 http://blog.csdn.net/niushuai666/article/details/7002823 http://hi.baidu.com/nial

一周总结4

一周总结 数论 POJ3058 题意:就是给定一个分数,要求把它化成二进制形式,求最小的循环节和循环节开始的位置. 首先约分化成最简分数形式p/q,然后化成二进制就是每次乘2大于1时,本位为1,该数取余,那么总会存在.则(p*2^i)%q=(p*2^j)%q,这里假设i<j,则可化为(p*2^(j-i))%q=1%q 因为gcd(p,q)==1,则2^(j-i)%q=1%q;这时就会想到欧拉公式,枚举q%2^(j-i)的欧拉函数值的因子就行了. POJ3696 题意:给定一个数字L,问是否存在一

图论 500题——主要为hdu/poj/zoj

转自——http://blog.csdn.net/qwe20060514/article/details/8112550 =============================以下是最小生成树+并查集======================================[HDU]1213   How Many Tables   基础并查集★1272   小希的迷宫   基础并查集★1325&&poj1308  Is It A Tree?   基础并查集★1856   More i