p1951

 

第一眼看到以为也是贪心(毕竟毕竟喜欢贪心的题)。

本题中要求把一个数列改成单调的数列,允许全为一个数。求改动的最少的次数。

最基础的想法是先求出每个位置以前包括自己1、2、3的个数sum1[i],sum2[i],sum3[i]。然后再枚举一的截止位点和二的截止位点,次数就可以直接求出。

公式如下(i取0到n,f取i到n)

1 2 3递增序列
ans=min(n-sum1[i]-sum2[f]+sum2[i]-sum3[n]+sum3[f],ans);
3 2 1递减序列
ans=min(n+sum1[f]-sum1[n]+sum2[i]-sum2[f]-sum3[i],ans);

这样下来复杂度是n^2,我不知道咋算的以为不会超时,以为应该是正解了吧,但被打脸了。(但是由于过水的数据还拿了90分)

想正解的过程中先想到的是空间换时间,然后一个动态规划的写法就很快出炉了:

在递增的时候维护ans[1][i] 、ans[2][i]、ans[3][i]分别表示第i个数为1、2、3时改动的个数,那么有这样的转移方程(minn返回三者的最小值)

//自己理解吧
ans[1][i]=ans[1][i-1];
ans[2][i]=min(ans[1][i-1],ans[2][i-1]);
ans[3][i]=minn(ans[1][i-1],ans[2][i-1],ans[3][i-1]);

if(o[i]==1)
{
    ans[2][i]++;
    ans[3][i]++;
}
if(o[i]==2)
{
    ans[1][i]++;
    ans[3][i]++;
}
if(o[i]==3)
{
    ans[1][i]++;
    ans[2][i]++;
}

相似的,递减的时候可以这样弄

ans[3][i]=ans[3][i-1];
ans[2][i]=min(ans[3][i-1],ans[2][i-1]);
ans[1][i]=minn(ans[3][i-1],ans[2][i-1],ans[1][i-1]);

if(o[i]==3)
{
    ans[2][i]++;
    ans[1][i]++;
}
if(o[i]==2)
{
    ans[3][i]++;
    ans[1][i]++;
}
if(o[i]==1)
{
    ans[3][i]++;
    ans[2][i]++;
}

最后的答案是两次循环后在ans[1/2/3][n]中取最小值。

本题AC

 

posted @ 2018-06-26 19:04  zzuqy  阅读(139)  评论(0编辑  收藏  举报