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; }