POJ_3670

    由于递增和递减是类似的,下面不妨只讨论变成递增序列的情况。

    由于Di只有三个数,所以可以考虑将序列分割成三部分,第一部分全部变成1,第二部分全部变成2,第三部分全部变成3。然后我们枚举3开始的位置,这时一共有若干决策,要么前面的全部是1,要么前面有一段2,然后再前面有一段1或者没有,如果每种决策都考察一遍的话整体复杂度就要O(N^2)了,因此考虑优化一下。记当前的位置为i,1的最后一个位置为j,not1[k]表示k以及k之前不是1的数量,not2[k]表示k以及k之前不是2的数量,not3[k]表示k以及k之后不是3的数量,那么我们把决策表示成not2[i]+(not1[j]-not2[j])+not3[i+1],这样如果我们保留着前面所有j中not1[j]-not2[j]的最小值的话,就可以O(1)找到最优决策了。

    这个题目还有一个很好的思路就是直接求最长不降子序列,然后用N减去这个值,不过这样最好也只是O(NlogN)的复杂度。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXD 30010
#define INF 0x3f3f3f3f
int N, not3[MAXD], a[MAXD];
void init()
{
    int i;
    for(i = 1; i <= N; i ++) scanf("%d", &a[i]);
}
int deal()
{
    int i, not1, not2, ans, opt;
    not3[N + 1] = 0;
    for(i = N; i >= 1; i --) not3[i] = not3[i + 1] + (a[i] != 3);
    ans = not3[1], not1 = not2 = opt = 0;
    for(i = 1; i <= N; i ++)
    {
        if(a[i] != 1) ++ not1;
        if(a[i] != 2) ++ not2;
        opt = std::min(opt, not1 - not2);
        ans = std::min(ans, not2 + opt + not3[i + 1]);
    }
    return ans;
}
void solve()
{
    int i, ans = deal();
    for(i = 1; i <= N / 2; i ++) std::swap(a[i], a[N - i + 1]);
    ans = std::min(ans, deal());
    printf("%d\n", ans);
}
int main()
{
    while(scanf("%d", &N) == 1)
    {
        init();
        solve();
    }
    return 0;
}

 

 

 

posted on 2012-09-28 11:27  Staginner  阅读(324)  评论(0编辑  收藏  举报