USACO 2017 January Contest Gold T2: Hoof, Paper, Scissors

题目大意

你可能听说过“石头,剪刀,布”的游戏。FJ的牛喜欢玩一个类似的游戏,它们称之为“蹄子,剪刀,布”(“蹄子”就是“石头”)。

游戏规则很简单:比赛双方同时数到3,然后同时出一个手势,代表“蹄子”“剪刀”或“布”。“蹄子”胜“剪刀”,“剪刀”胜“布”,“布”胜“蹄子”。举个例子,第一头牛出“蹄子”,第二头牛出“布”,则第二头牛胜利。当然,也可以“平局”(如果两头牛手势相同的话)。

FJ想对阵自己获奖的牛,贝西。贝西作为一个专家,能够预测FJ的手势。不幸的是,贝西作为一头牛,也十分的懒惰。事实上,她只愿意变换固定次数的手势来完成游戏。例如,她可能只想变1次,则他可能出“蹄子”几次,剩下的都出“布”。

他们一共玩 N  (1N100,000)轮,贝西愿意改变K (0K20)次手势。

鉴于贝西预测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\n",ans);
33     return 0;
34 }

 

posted @ 2019-07-22 21:01  LI_dox  阅读(281)  评论(0编辑  收藏  举报