标签:amp roman char careful getch lin when str 字符
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3536 Accepted Submission(s):
1153
题意:
给出m个模式串,每个串有一定的分值,构造一个长度不超过n的串,使得分值最大,并输出该字符串
在分数同样大时,输出长度最小的
长度一样时输出字典序最小的
HDU2296是一道有Bug的题目...............题目本身有表述不清楚导致有歧义........没有说明字符串后缀重合应该怎么处理.........所以说有两种程序可以通过本题,一种是Trie树正着插入、不管后缀重合、然后在AC自动机上DP时记录整个字符串,还有一种是Trie树倒着插入、后缀重合时权值都算上、DP时只记录转移来的状态...................然后本题字典序判断用Tire树的DFS序绝对不对,这个DFS序不能表达出整个生成的字符串的字典序............并且我一开始求DFS序是在建完AC自动机后求的,我的AC自动机是用了Trie图优化的,所以我就眼睁睁的看着为什么Trie树上的dfs一直停不下来............................................不要问我为什么花了一晚上
冷静的说做法:套路DP,f[i][j]生成到i AC自动机上走到j 的最大权值,记录pa[i][j]转移来的状态 字典序最小所以倒着插入 遇到相同暴力往前比较就行了
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N=1005,M=105,INF=1e9; inline int read(){ char c=getchar();int x=0,f=1; while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();} while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();} return x*f; } int n,m,w[N]; char s[15]; struct node{ int ch[27],val,fail,w; char c; }t[N]; int sz; void ins(char s[],int id){ int u=0,n=strlen(s+1); reverse(s+1,s+1+n); for(int i=1;i<=n;i++){ int c=s[i]-‘a‘; if(!t[u].ch[c]) t[u].ch[c]=++sz; u=t[u].ch[c]; t[u].c=s[i]; } t[u].val=id; } int q[N],head,tail; void getAC(){ head=tail=1; for(int i=0;i<26;i++) if(t[0].ch[i]) q[tail++]=t[0].ch[i]; while(head!=tail){ int u=q[head++]; t[u].w=w[t[u].val]; t[u].w+=t[t[u].fail].w; //val ??? for(int i=0;i<26;i++){ int &v=t[u].ch[i]; if(!v) v=t[t[u].fail].ch[i]; else{ t[v].fail=t[t[u].fail].ch[i]; q[tail++]=v; } } } } //int dfn[N],dfc; //void dfs(int u){ // dfn[u]=++dfc; //printf("dfs %d %d %c\n",u,dfn[u],t[u].c); // for(int i=0;i<26;i++) if(t[u].ch[i]) dfs(t[u].ch[i]); //} int f[55][N],pa[55][N]; bool cmp(int a,int b,int i){//a<b //printf("cmp %d %d %d\n",a,b,i); while(t[a].c==t[b].c) a=pa[i][a],b=pa[i][b],i--;//,printf("cmp %d %d %d\n",a,b,i); return t[a].c<t[b].c; } void lalala(int i,int j){ if(i==0) return; putchar(t[j].c); lalala(i-1,pa[i][j]); } void dp(){ memset(f,-1,sizeof(f)); f[0][0]=0; for(int i=0;i<n;i++) for(int j=0;j<=sz;j++) if(f[i][j]!=-1){ // printf("use %d %d %d %d\n",i,j,f[i][j],pa[i][j]); for(int k=0;k<26;k++){ int p=t[j].ch[k]; int _=f[i][j]+t[p].w;//printf("k %d %d %d %d\n",k,p,_,f[i+1][p]); if(_>f[i+1][p]) f[i+1][p]=_,pa[i+1][p]=j; else if(_==f[i+1][p]&&j!=pa[i+1][p]&&cmp(j,pa[i+1][p],i)) pa[i+1][p]=j; } } int ans=-1,ai=0,aj=0; for(int i=1;i<=n;i++) for(int j=0;j<=sz;j++){//printf("f %d %d %d %d\n",i,j,f[i][j],pa[i][j]); if(f[i][j]>ans) ans=f[i][j],ai=i,aj=j; else if(f[i][j]==ans&&i==ai&&cmp(j,aj,i)) ans=f[i][j],aj=j;//,printf("dfn %d %d %d\n",i,j,f[i][j]); } //printf("ans %d %d %d\n",ans,ai,aj); if(ans!=0) lalala(ai,aj); puts(""); } int main(){ freopen("in","r",stdin); int T=read(); while(T--){ memset(t,0,sizeof(t));sz=0; n=read();m=read(); for(int i=1;i<=m;i++) scanf("%s",s+1),ins(s,i); for(int i=1;i<=m;i++) w[i]=read(); getAC(); //for(int i=1;i<=sz;i++) printf("check %d %d %c\n",i,t[i].val,t[i].c); dp(); } }
标签:amp roman char careful getch lin when str 字符
原文地址:http://www.cnblogs.com/candy99/p/6368646.html