Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 263 | Accepted: 86 |
Description
In order to protect the money he is going to make, he needs to pick a special password for his bank account, satisfying the following requirements:
The password should not be too complex, so that Stanescu can remember it. The complexity of a password is the sum of the complexity of its characters and the complexity of a character is its position in the alphabet (for ’a’ it is 1, for ’b’ – 2, and so on).
For example, the complexity of the string ”ala” is 1 + 12 + 1 = 14;
It should match a given pattern string (composed of lowercase Latin letters, ’?’ and ’*’, no longer than 1000 characters). ’?’ is matched by one arbitrary lowercase Latin letter, and ’*’ – by zero or more arbitrary lowercase Latin letters;
It should be a sub-string of given super-password string (composed of lowercase Latin letters, no longer than 10000).
You have to write a program that computes the complexity of simplest possible password.
Input
Output
Sample Input
a?a alabala a*c?a axcbaabcbax
Sample Output
4 9
Hint
Test case #1: aba is the simplest password
Test case #2: abcba is simpler than axcba
/*
dp[i][j]代表模式串的第i个和原串的第j个匹配的时候最小值。
对于?
dp[i][j]=dp[i-1][j-1]+cost[j,j]
对于字母,要求mat[i]==pat[j]才能转移。
dp[i][j]=dp[i-1][j-1]+cost[j,j]
sum[i]代表原串前i个代价的总和
对于*
dp[i][j]=min{dp[i-1][k]+cost[k+1,j]} for k>=0&&k<=j
对于这个式子的话看起来要枚举K,这样显然不行。
我们可以转化
dp[i-1][k]+cost[k+1,j]
=dp[i-1][k]+sum[j]-sum[k]=(dp[i-1][k]-sum[k])+sum[j]
(dp[i-1][k]-sum[k])这个是一个只和k有关的式子。
我们可以保存一个(dp[i-1][k]-sum[k])最小值。这样就可以o(1)得到dp[i][j]了。
*/
#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
char str[1050],pass[10050];
int sum[10050],record[27],dp[1005][10050];
int main ()
{
int i,j,cur,n,m;
bool flag;
while(scanf("%s%s",str+1,pass+1)!=EOF)
{
n=strlen(str+1);
m=strlen(pass+1);
sum[0]=0;
for(i=0;i<26;i++)
record[i]=0;
for(i=1;i<=m;i++)
{
record[pass[i]-'a']++;
}
for(i=1;i<=n;i++)
{
if(str[i]>='a')//没想到问题出在这,数组越界了oj尽然没提示RE却提示WA
record[str[i]-'a']--;
}
for(i=0;i<26;i++)
{
if(record[i]<0)
break;
}
if(i<26)//这是最开始的优化,明显不合题意的去掉
{
printf("-1\n");
continue;
}
for(i=1;i<=m;i++)
{
sum[i]=pass[i]-'a'+1+sum[i-1];
}
for(i=0;i<=n;i++)
for(j=0;j<=m;j++)
dp[i][j]=10000000;
for(i=0;i<=m;i++)//str[1]得特殊操作,给dp[1][j]一个初始值
{
if(i>0&&(str[1]=='?'||str[1]==pass[i]))//第一位为?或者和pass[i]相等那dp[1][i]当然就是str[1]对应的值也是sum[i]-sum[i-1]
{
dp[1][i]=sum[i]-sum[i-1];
}
else if(str[1]=='*')//*有点特殊,它的取值是不定的,但是这题要求最小的值,如果str第一个为*,那我们完全可以不取任何值,也就是0
{
dp[1][i]=0;
}
}
for(i=2;i<=n;i++)
{
flag=0;
if(str[i]=='*')
{
cur=10000000;
if(dp[i-1][0]==0)
{
flag=1;
dp[i][0]=0;
cur=0;//记录一下最小值
}
for(j=1;j<=m;j++)
{
if(dp[i-1][j]-sum[j]<cur)
cur=dp[i-1][j]-sum[j];
if(sum[j]+cur<dp[i][j])
{
dp[i][j]=sum[j]+cur;
flag=1;
}
}
}
else
{
for(j=1;j<=m;j++)
{
if(dp[i-1][j-1]==10000000)
continue;//简化运算
if(str[i]=='?'||str[i]==pass[j])
{
if(dp[i][j]>dp[i-1][j-1]+pass[j]-'a'+1)
{
dp[i][j]=dp[i-1][j-1]+pass[j]-'a'+1;
flag=1;
}
}
}
}
if(!flag)//若flag为0,那就说明上面没有任何操作,没有符合条件的情况了,找不到适合的解了
break;
}
if(i<=n)//程序没有全部执行,str并没有在pass中全部找到
{
printf("-1\n");
continue;
}
cur=100000000;
for(i=0;i<=m;i++)//应该是从零开始,如果str是*结果就是0
{
if(cur>dp[n][i])//str中的字母都找完了
cur=dp[n][i];
}
if(cur==100000000)
printf("-1\n");
else
printf("%d\n",cur);
}
return 0;
}