托米没有完成上一个任务,准备施展黑魔法推倒 1317
黑魔法咒语被描述为一个 长为 n 的,仅包含小写英文字母 'a'...'i' 的字符串,在托米所在的星球,魔法造成的每次有效伤害都是来自他的一个子序列,对于每一个 'a'... 'i' 的排列(共 9! 种),若作为咒语的子序列出现, 就会造成 1 的伤害
而咒语的总伤害为所有 'a'... 'i' 的排列造成的伤害值之和,托米能打出多少点的伤害,是否能击败 1317 呢?
输入描述:
一行输入一个字符串 s
输出描述:
一行输出一个数,表示伤害值
示例1
输入
aabcdefghi
输出
1
备注:
|s| ≤ 3000
题意:给出一个大串,要求在大串中找a~i的全排列个数。大串中重复的全排列不计入。(限时1s)
历程/思路:本来是一道很水的题,用STL中的全排列函数就能卡过,时间大概在800,900ms左右,或者处理一下大串中字母的位置就能达到10ms左右的样子,但是中间出了很多毛病。最开始是用的string+全排列,过百分之80,超时。然后有大佬告诉我这道题暴力是能过的,苦苦寻找超时的原因,最后学长认为是++i与i++的问题,还查阅了相关的资料还真的神tm有点问题(i++与++i的效率问题:https://blog.csdn.net/linuxdriverdeveloper/article/details/8767563)然后第二天高高兴兴的复盘,结果。。。为毛i++能过呀,完全不是这个东西的问题啊......算了,也是涨见识了,以后要改改++的习惯了。
不处理全排列暴力做法(900ms左右):
#include<bits/stdc++.h>
using namespace std;
int main()
{
char a[10]="abcdefghi";
char b[5000];
int sum=0;
cin>>b;
do{
int t=0,i=0;
while(t<9&&b[i])
{
if(a[t]==b[i])
{
++t;
++i;
}
else{
++i;
}
}if(t==9)
{
sum++;
}
}while(next_permutation(a,a+9));
cout<<sum;
}
处理后再全排列做法(9ms):
#include<bits/stdc++.h>
using namespace std;
int num[10];
int dp[3010][10];
int main()
{
string s;
cin>>s;
s=' '+s;
for(int i=s.size()-1;i>=0;i--)
{
for(int j=0;j<=9;j++) dp[i][j]=num[j];//初始化操作
if(i!=0)num[s[i]-'a']=i;//num存字母在原串中的位置
}
char v[10]={"abcdefghi"};
int ans=0;
do{
int flag=0;
for(int i=0;i<9;i++)
{
flag=dp[flag][v[i]-'a'];//判断顺序是否符合
if(flag==0)
{
ans--;
break;
}
}
ans++;
}while(next_permutation(v,v+9));
cout<<ans<<endl;
return 0;
}