1. 程式人生 > >BZOJ5196: [Usaco2018 Feb]Taming the Herd(DP暴力)

BZOJ5196: [Usaco2018 Feb]Taming the Herd(DP暴力)

5196: [Usaco2018 Feb]Taming the Herd

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 78  Solved: 71
[Submit][Status][Discuss]

Description

一大清早,Farmer John就被木材破裂的聲音吵醒了。是這些奶牛們乾的,她們又逃出牛棚了!Farmer John已經厭 煩了奶牛在清晨出逃,他覺得受夠了:是時候採取強硬措施了。他在牛棚的牆上釘了一個計數器,追蹤從上次出逃 開始經過的天數。所以如果某一天早上發生了出逃事件,這一天的計數器就為0;如果最近的出逃是3天前,計數器 讀數就為3。Farmer John一絲不苟地記錄了每一天計數器的讀數。年末到了,Farmer John準備做一些統計。他說 ,你們這些奶牛會付出代價的!然而他的某些記錄看上去不太對勁……Farmer John想要知道從他開始記錄以來發 生過多少次出逃。但是,他懷疑這些奶牛篡改了它的記錄,現在他所確定的只有他是從發生出逃的某一天開始記錄 的。請幫助他求出,對於每個從他開始記錄以來可能發生的出逃次數,他被篡改了的記錄條數的最小值。

Input

輸入的第一行包含一個整數N(1≤N≤100),表示從Farmer John開始對奶牛出逃計數器進行計數以來已經經過的天數。 第二行包含N個空格分隔的整數。 第i個整數是一個非負整數ai(不超過100),表示在第i天計數器的數字是ai,除非奶牛篡改了這一天的記錄條目。

Output

輸出包含N個整數,每行一個。 第i個整數為所有發生i次出逃的事件序列中,與該事件序列不一致的記錄條目條數的最小值。

Sample Input

6
1 1 2 0 0 1

Sample Output

4
2
1
2
3
4
如果只發生1次出逃,則正確的記錄應該為0 1 2 3 4 5,有4處與給定的記錄不同。
如果發生2次出逃,則正確的記錄可能為0 1 2 3 0 1,有2處與給定的記錄不同。
在這個例子中,出逃發生在第一天和第五天。
如果發生3次出逃,則正確的記錄可能為0 1 2 0 0 1,僅有1處與給定的記錄不符。
在這個例子中,出逃發生在第一天、第四天和第五天。
以此類推。

 

思路:dp[i][j][k]表示第i個數以k結尾的,且用了j個0的最小修改次數,然後可以得到O(N^3)的 方程。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=110;
const int inf=0x3f3f3f3f;
int N,a[maxn],dp[maxn][maxn][maxn],ans[maxn];
int main(){
    scanf("%d",&N); rep(i,1
,N) scanf("%d",&a[i]); memset(dp,0x3f,sizeof(dp)); memset(ans,0x3f,sizeof(ans)); dp[1][1][0]=(a[1]!=0); rep(i,2,N){ rep(j,1,i){ rep(k,0,i-j) dp[i][j][0]=min(dp[i][j][0],dp[i-1][j-1][k]+(a[i]!=0)); rep(k,1,i-j) dp[i][j][k]=min(dp[i][j][k],dp[i-1][j][k-1]+(a[i]!=k)); } } rep(i,1,N) rep(j,0,N) ans[i]=min(ans[i],dp[N][i][j]); rep(i,1,N) printf("%d\n",ans[i]); return 0; }