打字
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);
}
}