Invoker
Problem Description
在 dota2 中有一个叫做祈求者(Invoker)的英雄,在游戏中他有三个基础技能:冰(Quas),雷(Wex),火(Exort),每施展一个技能就可以获得相应属性的一个法球(element)。
但是祈求者同时最多只能有三个法球,即如果他在有三个法球的状态下又使用了某个法球技能,那么他会获得该法球,并失去之前三个法球中最先获得的一个。
不难得出,祈求者身上的三个法球的**无顺序**组合有 10 种,每一种都对应着一个组合技能:
1. 急速冷却(Cold Snap),无序组合 QQQ,用 Y 表示
2. 幽灵漫步(Ghost Walk),无序组合 QQW,用 V 表示
3. 寒冰之墙(Ice Wall),无序组合 QQE,用 G 表示
4. 电磁脉冲(EMP),无序组合 WWW,用 C 表示
5. 强袭飓风(Tornado),无序组合 QWW,用 X 表示
6. 灵动迅捷(Alacrity),无序组合 WWE,用 Z 表示
7. 阳炎冲击(Sun Strike),无序组合 EEE,用 T 表示
8. 熔炉精灵(Forge Spirit),无序组合 QEE,用 F 表示
9. 混沌陨石(Chaos Meteor),无序组合 WEE,用 D 表示
10. 超震声波(Deafening Blast),无序组合 QWE,用 B 表示
当祈求者拥有三个法球的时候,使用元素祈唤(Invoke)技能,用 R 表示,便可获得当前法球组合所对应的技能,同时原有的三个法球也不会消失,先后顺序的状态也不会改变。
现在给定一个技能序列,你想按照给定的顺序将他们一个一个地祈唤出来,同时你想用最少的按键来达到目标,所以你想知道对于给定的一个技能序列,最少按多少次键才能把他们都祈唤出来。
注意:游戏开始的时候,祈求者是没有任何法球的。
Input
仅一行一个字符串 s,表示技能序列。其中所有字母都是大写,且在 {B,C,D,F,G,T,V,X,Y,Z} 内。
1≤|s|≤105
Output
仅一行一个正整数,表示最少按键次数。
Sample Input
XDTBV
Sample Output
14
Hint
一种按键最少的方案为:QWWREERERWQRQR
思路:暴力DP,把当前可行的情况枚举出来,然后跟之前枚举的匹配进行递推。
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #include<map> 7 #include<set> 8 #include<vector> 9 #include<queue> 10 #include<list> 11 #include<stack> 12 //#include<unordered_map> 13 using namespace std; 14 #define ll long long 15 #define dd cout<<endl 16 #define lll __int128 17 const int mod=1e9+7; 18 const int inf=1e9+7; 19 20 const int maxn=1e6+10; 21 22 int dp[maxn][10]; 23 24 int main() 25 { 26 ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 27 28 string str; 29 30 while(cin>>str) 31 { 32 memset(dp,0X3f3f3f,sizeof(dp)); 33 34 string last[6]; 35 36 string now[6]; 37 38 for(int i=0;i<str.size();i++) 39 { 40 if(str[i]=='Y') 41 { 42 now[0]="QQQ",now[1]="QQQ",now[2]="QQQ"; 43 now[3]="QQQ",now[4]="QQQ",now[5]="QQQ"; 44 } 45 else if(str[i]=='V') 46 { 47 now[0]="QQW",now[1]="QWQ",now[2]="QQW"; 48 now[3]="QWQ",now[4]="WQQ",now[5]="WQQ"; 49 } 50 else if(str[i]=='G') 51 { 52 now[0]="EQQ",now[1]="EQQ",now[2]="QEQ"; 53 now[3]="QQE",now[4]="QEQ",now[5]="QQE"; 54 } 55 else if(str[i]=='C') 56 { 57 now[0]="WWW",now[1]="WWW",now[2]="WWW"; 58 now[3]="WWW",now[4]="WWW",now[5]="WWW"; 59 } 60 else if(str[i]=='X') 61 { 62 now[0]="QWW",now[1]="QWW",now[2]="WQW"; 63 now[3]="WWQ",now[4]="WQW",now[5]="WWQ"; 64 } 65 else if(str[i]=='Z') 66 { 67 now[0]="EWW",now[1]="EWW",now[2]="WEW"; 68 now[3]="WWE",now[4]="WEW",now[5]="WWE"; 69 } 70 else if(str[i]=='T') 71 { 72 now[0]="EEE",now[1]="EEE",now[2]="EEE"; 73 now[3]="EEE",now[4]="EEE",now[5]="EEE"; 74 } 75 else if(str[i]=='F') 76 { 77 now[0]="EEQ",now[1]="EQE",now[2]="EEQ"; 78 now[3]="EQE",now[4]="QEE",now[5]="QEE"; 79 } 80 else if(str[i]=='D') 81 { 82 now[0]="EEW",now[1]="EWE",now[2]="EEW"; 83 now[3]="EWE",now[4]="WEE",now[5]="WEE"; 84 } 85 else if(str[i]=='B') 86 { 87 now[0]="EQW",now[1]="EWQ",now[2]="QEW"; 88 now[3]="QWE",now[4]="WEQ",now[5]="WQE"; 89 } 90 91 if(i==0) 92 { 93 for(int j=0;j<6;j++) 94 { 95 dp[i][j]=3; 96 } 97 } 98 else 99 { 100 for(int j=0;j<6;j++) 101 { 102 for(int k=0;k<6;k++) 103 { 104 string pre=last[k],nxt=now[j]; 105 106 int cnt; 107 108 if(pre[0]==nxt[0]&&pre[1]==nxt[1]&&pre[2]==nxt[2]) 109 cnt=3; 110 else if(pre[1]==nxt[0]&&pre[2]==nxt[1]) 111 cnt=2; 112 else if(pre[2]==nxt[0]) 113 cnt=1; 114 else 115 cnt=0; 116 117 dp[i][j]=min(dp[i][j],dp[i-1][k]+(3-cnt)); 118 119 } 120 121 } 122 } 123 124 for(int j=0;j<6;j++) 125 { 126 last[j]=now[j]; 127 } 128 129 } 130 131 int minn=dp[(int)str.size()-1][0]; 132 133 for(int i=0;i<6;i++) 134 { 135 if(dp[(int)str.size()-1][i]<minn) 136 minn=dp[(int)str.size()-1][i]; 137 } 138 139 cout<<minn+str.size()<<endl; 140 141 } 142 143 return 0; 144 }