1. 程式人生 > >[BZOJ1609][Usaco2008 Feb]Eating Together麻煩的聚餐

[BZOJ1609][Usaco2008 Feb]Eating Together麻煩的聚餐

想要 problems stat i++ 是個 using sample 中間 升序

1609: [Usaco2008 Feb]Eating Together麻煩的聚餐

Time Limit: 10 Sec Memory Limit: 64 MB Submit: 1653 Solved: 1010 [Submit][Status][Discuss]

Description

為了避免餐廳過分擁擠,FJ要求奶牛們分3批就餐。每天晚飯前,奶牛們都會在餐廳前排隊入內,按FJ的設想所有第3批就餐的奶牛排在隊尾,隊伍的前端由設定為第1批就餐的奶牛占據,中間的位置就歸第2批就餐的奶牛了。由於奶牛們不理解FJ的安排,晚飯前的排隊成了一個大麻煩。 第i頭奶牛有一張標明她用餐批次D_i(1 <= D_i <= 3)的卡片。雖然所有N(1 <= N <= 30,000)頭奶牛排成了很整齊的隊伍但誰都看得出來,卡片上的號碼是完全雜亂無章的。 在若幹次混亂的重新排隊後,FJ找到了一種簡單些的方法:奶牛們不動,他沿著隊伍從頭到尾走一遍把那些他認為排錯隊的奶牛卡片上的編號改掉,最終得到一個他想要的每個組中的奶牛都站在一起的隊列,例如111222333或者333222111。哦,你也發現了,FJ不反對一條前後顛倒的隊列,那樣他可以讓所有奶牛向後轉,然後按正常順序進入餐廳。 你也曉得,FJ是個很懶的人。他想知道,如果他想達到目的,那麽他最少得改多少頭奶牛卡片上的編號。所有奶牛在FJ改卡片編號的時候,都不會挪位置。

Input

第1行: 1個整數:N 第2..N+1行: 第i+1行是1個整數,為第i頭奶牛的用餐批次D_i

Output

第1行: 輸出1個整數,為FJ最少要改幾頭奶牛卡片上的編號,才能讓編號變成他設想中的樣子

Sample Input

5
1
3
2
1
1
輸入說明:

隊列中共有5頭奶牛,第1頭以及最後2頭奶牛被設定為第一批用餐,第2頭奶牛的預設是第三批用餐,第3頭則為第二批用餐。

Sample Output

1

輸出說明:

如果FJ想把當前隊列改成一個不下降序列,他至少要改2頭奶牛的編號,一種可行的方案是:把隊伍中2頭編號不是1的奶牛的編號都改成1。不過,如果FJ選擇把第1頭奶牛的編號改成3就能把奶牛們的隊伍改造成一個合法的不上升序列了。
設$dp[i][j]$表示修改前$i$位使得其合法且最後一位為$j$的最小代價,正反各做一次即可,時間復雜度$O(n)$
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 30000 + 10;
int a[maxn], b[maxn];
int dp[maxn][4];
int main(){
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++){
        scanf("
%d", a + i); b[n - i + 1] = a[i]; } dp[1][1] = dp[1][2] = dp[1][3] = 1; dp[1][a[1]] = 0; for(int num, i = 2; i <= n; i++){ num = dp[i - 1][1]; for(int j = 1; j <= 3; j++){ dp[i][j] = num + (a[i] != j); num = min(num, dp[i - 1][j + 1]); } } int ans = 66662333; for(int i = 1; i <= 3; i++) ans = min(ans, dp[n][i]); dp[1][1] = dp[1][2] = dp[1][3] = 1; dp[1][b[1]] = 0; for(int num, i = 2; i <= n; i++){ num = dp[i - 1][1]; for(int j = 1; j <= 3; j++){ dp[i][j] = num + (b[i] != j); num = min(num, dp[i - 1][j + 1]); } } for(int i = 1; i <= 3; i++) ans = min(ans, dp[n][i]); printf("%d\n", ans); return 0; }

[BZOJ1609][Usaco2008 Feb]Eating Together麻煩的聚餐