Luogu【P3609】蹄子剪刀布(DP+滚动数组)

  题目链接

  (突然高兴

  又一次瞬间想出转移方程并一遍A掉!!233333(虽然从二叉苹果树那题开始我就发现我的方程好像跟别人不大一样

  (所以这样就可以名正言顺的水题解了

  设f[i][j][k]表示考虑FJ出的前i个手势,Bessie变了j次之后,用k表示的手势到目前为止赢了FJ的最多次数。

  则考虑FJ出的第i个手势,有两种情况:

  1.Bessie懒得变手势并秒杀FJ。

  2.Bessie从石头剪刀布变到了胜利手势并秒杀FJ。

  所以状态转移方程比较好想了。

  然而f[100000][20][3]=f[6000000]=内存超级大

  所以我用了滚动数组。只存上一个状态就可以了。

  代码如下

#include<cstdio>
#include<cctype>
#include<algorithm>
#include<cstring>
using namespace std;
inline long long max(long long a,long long b){    return a>b?a:b;    }
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

int f[3][25][5];

int main(){
    int n=read(),k=read();
    for(int i=1;i<=n;++i){
        char cc[10];
        int opt;
        scanf("%s",cc);
        char c=cc[0];
        if(c=='H')        opt=1;
        else if(c=='S')    opt=2;
        else             opt=3;
        int t=opt-1;
        if(t==0)    t=3;
        
        for(int j=0;j<=k;++j){
            f[2][j][t]=f[1][j][t];
            for(int l=1;l<=3;++l)
                if(f[2][j][t]<f[1][j-1][l])    f[2][j][t]=f[1][j-1][l];
            f[2][j][t]++;
        }
        for(int j=0;j<=k;++j)
            for(int l=1;l<=3;++l){
                if(f[2][j][l])    f[1][j][l]=f[2][j][l];
                f[2][j][l]=0;
            }
    }
    
    int ans=f[1][k][1];
    if(ans<f[1][k][2])    ans=f[1][k][2];
    if(ans<f[1][k][3])    ans=f[1][k][3];
    printf("%d",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/cellular-automaton/p/7596160.html