祖玛游戏

f[i][j][0/1/2]表示在区间[i,j]左侧加 0,1,2 个和i颜色相同的球,并把[i,j]区间的球全部消除掉的最小花费。

if(k<2) ans = min(ans, dp(l,r,k+1)+1);那么可以在左侧再加1个
if(k==2) ans = min(ans, dp(l+1,r,0));那么a[l]和添加的两个就消除了,转成了f[l+1][r][0]

if(a[i]==a[l]){
ans = min(ans, dp(l+1,i-1,0)+dp(i,r,min(k+1,2)));
}把中间的f[l+1][i-1][0]的部分消除掉,两头的就碰在了一起,相当于在区间[i,r]的左侧添加了k+1,这个k+1是本来有k个,再算
上a[l],就成了k+1,因为超过两个就会被消掉,最后变成(k+1)%3。

#include <bits/stdc++.h>
#define inf 2333333333333333
#define N 1000010
#define p(a) putchar(a)
#define For(i,a,b) for(long long i=a;i<=b;++i)
//by war
//2020.10.22
using namespace std;
long long n;
long long a[N],f[2020][2020][3];
void in(long long &x){
    long long y=1;char c=getchar();x=0;
    while(c<'0'||c>'9'){if(c=='-')y=-1;c=getchar();}
    while(c<='9'&&c>='0'){ x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    x*=y;
}
void o(long long x){
    if(x<0){p('-');x=-x;}
    if(x>9)o(x/10);
    p(x%10+'0');
}

long long dp(long long l,long long r,long long k){
    if(l>r) return 0;
    if(~f[l][r][k]) return f[l][r][k];
    long long ans = inf;
    if(k<2) ans = min(ans, dp(l,r,k+1)+1);
    if(k==2) ans = min(ans, dp(l+1,r,0));
    For(i,l+1,r){
        if(a[i]==a[l]){
            ans = min(ans, dp(l+1,i-1,0)+dp(i,r,(k+1)%3));
        }
    }
    return f[l][r][k]=ans;
}

signed main(){
    memset(f,-1,sizeof f);
    in(n);
    For(i,1,n) in(a[i]);
    o(dp(1,n,0));
    return 0;
}
原文地址:https://www.cnblogs.com/war1111/p/13861024.html