[USACO21FEB] Modern Art 3 G

洛谷题面

完 全 一 样.jpg

题目大意

有一个长度为 \(N\) 的序列,初始时序列均为 \(0\)

可以对其进行区间赋值,求你至少需要几次操作能将该序列变为目标序列?

题目大意

一道原题,详见 \(\rm P4170\).

显然是一道区间 \(\rm DP\)

\(dp[i][j]\) 表示把区间 \([i,j]\) 内的数涂成目标颜色所需要的最少次数。

属性:\(\min\)

目标:\(dp[1][n]\)

令目标序列的第 \(i\) 个数为 \(a_i\),我们枚举区间左右边界 \(l,r\),不难得出方程:

\(a_l=a_r\) 时,\(dp[l][r]=\min\{dp[l+1][r],dp[l][r-1]\}\)

意思是:我们可以认为 \(l\) 是涂区间 \([l+1,r]\) 的时候顺便涂上的,或者 \(j\) 是涂 \([l,r-1]\) 的时候顺便涂上的。

否则,即当 \(a_l\neq a_r\) 时,\(dp[l][r]=\{dp[i][k]+dp[k+1][r]\}(l\leq k<r)\)

代码

const int ma=305;

int a[ma];

int dp[ma][ma];
//dp[i][j]:把区间 [i,j] 涂上目标颜色所需要的最少次数 

int sum; 

int main(void)
{
//	freopen("Art.in","r",stdin);
//	
//	freopen("Art.out","w",stdout);
	
	int n;
	
	scanf("%d",&n);
	
	memset(dp,0x3f,sizeof(dp));
	
	for(register int i=1;i<=n;i++)
	{
		scanf("%d",a+i);
		
		dp[i][i]=1;
	}
	
	for(register int len=2;len<=n;len++)
	{
		for(register int l=1;l<=n;l++)
		{
			int r=l+len-1;
			
			if(r>n)
			{
				break;
			}
			
			if(a[l]==a[r])
			{
				dp[l][r]=min(dp[l+1][r],dp[l][r-1]);
			}
			
			else
			{
				
				for(register int k=l;k<r;k++)
				{
					dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]);
				}
			}
		}
	}
	
	printf("%d\n",dp[1][n]);
	
	return 0; 
}
posted @ 2021-10-07 15:42  Coros_Trusds  阅读(128)  评论(0)    收藏  举报