$UVA10559 Blocks $区间$dp$

(Des)

• 有一排数量为N的方块,每次可以把连续的相同颜色的区间消除,得到分数为 区间长度的平方,然后左右两边连在一起,问最大分数为多少。

• n<=1

(Sol)

正解状态设得奇奇怪怪巧巧妙妙.

(f[i][j][k])表示区间([i,j])(j)右边还有(k)个和(j)同色的方块,消除所有这些的最大分数.转移分为两种:

1.将右端点和多出的(k)个一起消掉,分数为(f[i][j-1]+(k+1)^2).

2.选一个与右端点同色的点(p),消掉([p+1,j-1])使得(p,j)相邻,分数为(f[i][p][k+1]+f[p+1][j-1][0]).

那怎么样想到这个巧巧妙妙的状态呢:

首先这个题是有合并顺序的,可以考虑区间(dp),考虑对于区间([l,r])能不能通过枚举中间点(k),用([l,k],[k+1][r])转移.稍加思考就可以知道,这个亚子是不行的.这个题是"消消乐",可能中间的某个点会和边界一起消掉更优.于是就发现,这题并不是规规矩矩的区间$dp $,看能不能通过多记一维状态来解决这个问题...于是就聪聪明明地设出了这个状态强行.

这题好好写,瞎写一下就过了.

(Code)

Code ```cpp #include #include #include #define il inline #define Ri register int #define go(i,a,b) for(Ri i=a;i<=b;++i) #define yes(i,a,b) for(Ri i=a;i>=b;--i) #define e(i,u) for(Ri i=b[u];i;i=a[i].nt) #define mem(a,b) memset(a,b,sizeof(a)) #define ll long long #define db double #define inf 2147483647 using namespace std; il int read() { Ri x=0,y=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')y=-1;c=getchar();} while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();} return x*y; } const int N=210; int T,n,a[N],s[N],f[N][N][N]; int main() { //freopen(".in","r",stdin); //freopen(".out","w",stdout); T=read(); go(TT,1,T)//remember to init! { n=read(); go(i,1,n)a[i]=read(); mem(s,0);mem(f,0); go(i,1,n) go(j,i+1,n) if(a[i]==a[j])s[i]++; yes(i,n,1) go(j,i,n) go(k,0,s[j]) { f[i][j][k]=f[i][j-1][0]+(k+1)*(k+1); go(p,i,j-1) if(a[p]==a[j]) f[i][j][k]=max(f[i][j][k],f[i][p][k+1]+f[p+1][j-1][0]); } printf("Case %d: %d ",TT,f[1][n][0]); } return 0; } ```
原文地址:https://www.cnblogs.com/forward777/p/11592804.html