“师创杯”山东理工大学第九届ACM程序设计竞赛 正式赛 G.打字【Dp+贪心】水题

打字

Time Limit: 1000MS  Memory Limit: 65536KB
Problem Description

snow是个热爱打字的家伙,每次敲出更快的速度都会让他很开心。现在,他拿到一篇新的打字文章,已知这篇文章只有26个小写英文字母,给出snow打出这26个英文字母分别需要多少时间(s),问snow打完这篇文章获得的kpm最大为多少?kpm=打正确的字数/所花的分钟数,注意snow可能会打错一些字哦。打错的必定是文章里面存在的。

Input

多组输入

每组数据首先输出26个整数,分别表示打出a,b.c...z这26个字母需要的时间,时间保证是int范围内的正整数,然后给出一个字符串,长度不超过1000,保证只包含小写英文字母

Output

每组输出占一行,输出最大的kpm,保留2位小数

Example Input
1 2 2 1 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
abcd
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
abcd
Example Output
40.00
25.71
Hint
Author
Johsnows

思路:


如果比赛过程中题面没有错误就好了。


直接设定dp【i】【j】表示为到第i个字母,我们敲对了j个字母的最少时间花费。

那么对应有:


这里use【】表示打正确字母所用时间,fail【】表示打错误字母所用时间。

很显然,如果我们敲错,肯定是希望使用时间最短。这里预处理一下就行了。


Ac代码:

#include<stdio.h>
#include<string.h>
#include<map>
#include<iostream>
using namespace std;
#define ll long long int
ll use[30];
ll fail[30];
char a[10050];
ll dp[1205][1205];
ll INF=1000000000000000ll;
int main()
{
    while(~scanf("%lld",&use[0]))
    {
        map<char ,int >s;
        for(int j=1;j<=25;j++)scanf("%lld",&use[j]);
        scanf("%s",a+1);
        int n=strlen(a+1);
        for(int i=1;i<=n;i++)
        {
            s[a[i]]++;
        }
        for(int j=0;j<=25;j++)
        {
            fail[j]=INF;
            for(int k=0;k<=25;k++)
            {
                if(k==j||s[k+'a']==0)continue;
                fail[j]=min(fail[j],use[k]);
            }
        }
        for(int i=0;i<=n;i++)
        {
            for(int j=0;j<=n;j++)
            {
                dp[i][j]=INF;
            }
        }
        dp[0][0]=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<=i;j++)
            {
                if(j==0)
                {
                    dp[i][j]=min(dp[i][j],dp[i-1][j]+fail[a[i]-'a']);
                }
                else dp[i][j]=min(dp[i-1][j-1]+use[a[i]-'a'],dp[i-1][j]+fail[a[i]-'a']);
            }
        }
        double ans=-1000000000000000000.0;
        for(int j=1;j<=n;j++)
        {
            double tmpp=j*60;
            tmpp/=(double)dp[n][j];
            ans=max(ans,tmpp);
        }
        printf("%.2f\n",ans);
    }
}








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值