题目大意
你可能听说过“石头,剪刀,布”的游戏。FJ的牛喜欢玩一个类似的游戏,它们称之为“蹄子,剪刀,布”(“蹄子”就是“石头”)。
游戏规则很简单:比赛双方同时数到3,然后同时出一个手势,代表“蹄子”“剪刀”或“布”。“蹄子”胜“剪刀”,“剪刀”胜“布”,“布”胜“蹄子”。举个例子,第一头牛出“蹄子”,第二头牛出“布”,则第二头牛胜利。当然,也可以“平局”(如果两头牛手势相同的话)。
FJ想对阵自己获奖的牛,贝西。贝西作为一个专家,能够预测FJ的手势。不幸的是,贝西作为一头牛,也十分的懒惰。事实上,她只愿意变换固定次数的手势来完成游戏。例如,她可能只想变1次,则他可能出“蹄子”几次,剩下的都出“布”。
他们一共玩 N (1≤N≤100,000)轮,贝西愿意改变K (0≤K≤20)次手势。
鉴于贝西预测FJ会出的手势,以及她想变的次数,求出她最多能赢多少场
题目分析
观察数据范围 N很大,而K极小,所以可以考虑使用关于K来DP。
令 f[i][j][k] 代表第 i 回合最多换 j 次手势且当前情况下选的 k手势(代表蹄子,剪刀或者布)时赢的最多场次。
那么转移方程就很显然了,令pk表示手势 i对j 时 对 i 来说的胜负情况,赢为1,输为0
f[i][j][k] = max( f[i-1][j][k] + pk[k][a[ i ]], f[i-1][j-1][p(不同于k的另外手势)] + pk[k][a[i]] )
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAXN=1e5+10; 4 5 map<char,int> g; 6 int res[5][5]; 7 int n,k,ans; 8 int a[MAXN],f[MAXN][25][4]; 9 char ch; 10 inline void Init(){ 11 g['H']=1;g['S']=2;g['P']=3; 12 res[1][2]=1;res[2][3]=1;res[3][1]=1; 13 } 14 int main(){ 15 Init(); 16 scanf("%d%d",&n,&k); 17 for(int i=1;i<=n;++i){ 18 cin>>ch; 19 a[i]=g[ch]; 20 } 21 for(int i=1,x;i<=n;++i) 22 for(int j=0;j<=min(i,k);++j) 23 for(int p=1;p<=3;++p){ 24 x=res[p][a[i]]; 25 f[i][j][p]=max(f[i-1][j][p]+x,f[i][j][p]); 26 for(int q=1;q<=3;++q) 27 if(q!=p&&j) 28 f[i][j][p]=max(f[i][j][p],f[i-1][j-1][q]+x); 29 } 30 for(int i=1;i<=3;++i) 31 ans=max(f[n][k][i],ans); 32 printf("%d ",ans); 33 return 0; 34 }