戒指

题目

S计划送给J一枚戒指,以示他们的爱情天长地久
同时,S打算在戒指上刻写一些语句,以增加它的寓意。可惜戒指的大小有限,最多只能被刻入N个字母。细心的S非常了解J,知道她喜欢的单词,例如love, forever等等,同时他也知道这些单词都存在一个“愉悦值”,值越高的单词越能取悦J。
现在,S希望刻入一条字符串,使得各个单词在字符串中出现的次数 × 单词愉悦值之和尽可能的大。
1. 1 <= T <= 15
2. 1 <= N <= 50,1 <= M <= 100
3. 1 <= 单词长度 <= 10
4. 1 <= Hi <= 100
5. 数据保证不出现重复的单词
6. 对于每组数据输出一行,为在戒指上刻入的字符串。
如果有多解,则输出长度最短的解,若依然有多接则输出字典序最小的解。
答案有可能为空串。

分析

虽然这题的附加要求有很多:长度,字典序。
不过没关系,这题仍然可以用dp来处理。
具体的:
f[i,j]ij
same[i,j]ij
那么f[i+same[j,k],k]=max(f[i,j]+v[k],f[i+same[j,k],k])
而我们再记录两个值:
le[i,j]ans[i,j]ij
到此便可以很好的解决这个问题。
ps:我卡在这题很久的原因主要是same数组一直弄错。。还是要细心点,不要想当然,每一步都要经过严谨的思考来验证

var
    t,i,j,k,ma,n,m,k1,k2:longint;
    str:array[1..300] of string;
    len,v:array[1..300] of longint;
    c:array[1..500,1..300] of longint;
    f,le:array[1..500,1..300] of longint;
    ans:array[1..500,1..300] of string;we:string;
function max(l,r:longint):longint;
begin
    if l<r then exit(r);exit(l);
end;
function get(x,y:string):longint;
var i,j,lenx,leny,an,st:longint;p:boolean;
begin
    lenx:=length(x);leny:=length(y);an:=0;
    if x=y then st:=2 else st:=1;
    for i:=st to lenx do begin
        if lenx-i+1>leny then continue;P:=true;
        for j:=i to lenx do
            if x[j]<>y[j-i+1] then begin p:=false;break;end;
        if not p then continue;
        an:=max(an,lenx-i+1);
    end;exit(an);
end;
begin
    readln(t);
    for t:=1 to t do begin
        readln(n,m);
        for i:=1 to m do begin readln(str[i]);len[i]:=length(str[i]);end;
        for i:=1 to m do
            for j:=1 to m do begin
            c[i,j]:=get(str[i],str[j]);
            end;
        fillchar(f,sizeof(f),0);
        for i:=1 to 500 do
        for j:=1 to 300 do ans[i,j]:='';
        k:=k;
        for i:=1 to m do begin
            read(v[i]);
            f[len[i],i]:=v[i];
            ans[len[i],i]:=str[i];le[len[i],i]:=len[i];
        end; readln;
        for i:=1 to n do
            for j:=1 to m do if f[i,j]>0 then
                for k:=1 to m do begin
                    k2:=i+len[k]-c[j,k];
                    if f[k2,k]<f[i,j]+v[k] then begin
                       f[k2,k]:=f[i,j]+v[k];
                       k1:=len[k]-c[j,k];
                       ans[k2,k]:=ans[i,j]+copy(str[k],c[j,k]+1,k1);
                       le[k2,k]:=le[i,j]+k1;
                    end else
                    if (f[k2,k]=f[i,j]+v[k])and(le[k2,k]=le[i,j]+len[k]-c[j,k])and(ans[k2,k]>ans[i,j]+copy(str[k],c[j,k]+1,len[k]-c[j,k])) then begin
                         ans[k2,k]:=ans[i,j]+copy(str[k],c[j,k]+1,len[k]-c[j,k]);
                         le[k2,k]:=le[i,j]+len[k]-c[j,k];
                    end
                    else if (f[k2,k]=f[i,j]+v[k])and(le[k2,k]>le[i,j]+len[k]-c[j,k]) then begin
                         ans[k2,k]:=ans[i,j]+copy(str[k],c[j,k]+1,len[k]-c[j,k]);
                         le[k2,k]:=le[i,j]+len[k]-c[j,k];
                    end;
                end;
        ma:=0;we:='';
        for i:=1 to n do
            for j:=1 to m do
            if ma<f[i,j] then begin ma:=f[i,j];we:=ans[i,j];end
            else if (ma=f[i,j])and(we>ans[i,j]) then we:=ans[i,j];
        writeln(we);
    end;
close(input);close(output);
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值