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

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

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 1646  Solved: 1005
[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就能把奶牛们的队伍改造成一个合法的不上升序列了。

HINT

 

Source

Silver

 

Analysis

这是一道递推qwq

(然而我丧心病狂地去求最长升/降序,英勇送TLE)

定义状态为 DP[ 前 i 个数 ][ 以 j 结尾 ] = 最小修改次数

那么我们可以根据这个状态直接AC了..

代码中PD的意思就是逆过来DP嗯(严格来说不算DP)

 

Code

 1 #include<cstdio>
 2 #include<iostream>
 3 #define maxn 1000000
 4 //using namespace std;
 5 
 6 int min(int a,int b){return a<b?a:b;}
 7 int min(int a,int b,int c){return min(min(a,b),c);}
 8 
 9 int arr[maxn],DP[maxn][4],PD[maxn][4],n;
10 
11 int main(){
12     scanf("%d",&n);
13     
14     for(int i = 1;i <= n;i++){
15         scanf("%d",&arr[i]);
16         
17         switch(arr[i]){
18             case 1:
19                 DP[i][1] = DP[i-1][1];
20                 DP[i][2] = min(DP[i-1][1],DP[i-1][2]+1);
21                 DP[i][3] = min(DP[i-1][1],DP[i-1][2]+1,DP[i-1][3]+1);
22                 break;
23             case 2:
24                 DP[i][1] = DP[i-1][1]+1;
25                 DP[i][2] = min(DP[i-1][1],DP[i-1][2]);
26                 DP[i][3] = min(DP[i-1][1],DP[i-1][2],DP[i-1][3]+1);
27                 break;
28             case 3:
29                 DP[i][1] = DP[i-1][1]+1;
30                 DP[i][2] = min(DP[i-1][1]+1,DP[i-1][2]+1);
31                 DP[i][3] = min(DP[i-1][1],DP[i-1][2],DP[i-1][3]);
32                 break;
33         }
34     }
35     
36     for(int i = n;i >= 1;i--){
37         switch(arr[i]){
38             case 1:
39                 PD[i][1] = PD[i+1][1];
40                 PD[i][2] = min(PD[i+1][1],PD[i+1][2]+1);
41                 PD[i][3] = min(PD[i+1][1],PD[i+1][2]+1,PD[i+1][3]+1);
42                 break;
43             case 2:
44                 PD[i][1] = PD[i+1][1]+1;
45                 PD[i][2] = min(PD[i+1][1],PD[i+1][2]);
46                 PD[i][3] = min(PD[i+1][1],PD[i+1][2],PD[i+1][3]+1);
47                 break;
48             case 3:
49                 PD[i][1] = PD[i+1][1]+1;
50                 PD[i][2] = min(PD[i+1][1]+1,PD[i+1][2]+1);
51                 PD[i][3] = min(PD[i+1][1],PD[i+1][2],PD[i+1][3]);
52                 break;
53         }
54     }
55     
56     int ans = min(min(PD[1][1],PD[1][2],PD[1][3]),min(DP[n][1],DP[n][2],DP[n][3]));
57     
58     printf("%d",ans);
59     
60     return 0;
61 }
我被水题欺负嘤嘤嘤
posted @ 2017-08-31 19:16  μSsia  阅读(156)  评论(0编辑  收藏  举报