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

浙公网安备 33010602011771号