牛客练习赛23 D-托米的咒语 C++

题目:

链接:https://www.nowcoder.com/acm/contest/156/D
来源:牛客网
 

题目描述

托米没有完成上一个任务,准备施展黑魔法推倒 1317

黑魔法咒语被描述为一个 长为 n 的,仅包含小写英文字母 'a'...'i' 的字符串,在托米所在的星球,魔法造成的每次有效伤害都是来自他的一个子序列,对于每一个 'a'... 'i' 的排列(共 9! 种),若作为咒语的子序列出现, 就会造成 1 的伤害

而咒语的总伤害为所有 'a'... 'i' 的排列造成的伤害值之和,托米能打出多少点的伤害,是否能击败 1317 呢?

输入描述:

一行输入一个字符串 s

输出描述:

一行输出一个数,表示伤害值

示例1

输入

复制

aabcdefghi

输出

复制

1

备注: 

|s| ≤  3000

 思路:

补题ing,为了督促自己补完这题所以先把题目发在题解里。

比赛时没看懂这题啥意思,然后看了一下题解,大概是给你一个字符串,问它的子串有多少个是'a'-'i'的全排列中的字符串。

暴力了一下发现太慢了。

然后参考了一下题解https://blog.csdn.net/haut_ykc/article/details/81259754过于优秀……反正我是想不到这么妙的方法。

补充说明一下:

记录每一个位置开始时每个字母第一次出现的位置。这样可以把O(n)变成O(10)。

dp[i][k]表示从第i个字符开始字母k最早出现的位置。

比如给你一个样例bbabcdefg

那么在第一个字符开始的时候,字母a第一次出现的位置是3(从1开始),那就从第二个位置开始找下一个字母b,发现没有字母b,于是跳出这个排序,生成下一个全排列。全排列用STL里的next_permutation就好。

像这个样例用dp表示就是 dp[0][0]=3,dp[0][1]=1,dp[0][2]=5……dp[i][k]中的k表示字母,a就是0,b就是1,记录时用字母减去'a'就行。

代码:

#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<cstdio>
using namespace std;
int main()
{
    char a[3001];
    while(scanf("%s",a+1)!=EOF){
        int dp[3001][10],num[10];
        char ss[]="abcdefghi";
        memset(num,0,sizeof(num));
        for(int i=strlen(a+1);i>=0;i--){
            for(int j=0;j<9;j++){
                dp[i][j]=num[j];
            }
            if(i)num[a[i]-'a']=i;

        }
        int ans=0;
        do{
            int k=0;
            for(int i=0;i<9;i++){
                k=dp[k][ss[i]-'a'];
                if(!k)break;
            }
            if(k)ans++;
        }while(next_permutation(ss,ss+9));
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Zero_979/article/details/81264012