題解 P4267 【[USACO18FEB]Taming the Herd】
阿新 • • 發佈:2020-09-04
說實話感覺不是一道藍題……感覺挺水的,不過為了水題解,水題就夠了(其實是覺得思考的過程比較典型,記錄一下)
題解
剛開始看這道題感覺上沒什麼思路,但是我們可以先考慮用 \(O(n)\) 的時間去枚舉發生的出逃次數,再用 \(O(n^2)\) 的時間去計算每一個出逃次數的情況下不一致條目的最小值。
現在我們考慮對於任意一個出逃次數 \(d\) ,我們如何計算。不妨設 \(f_{i,j}\) 表示到第 \(i\) 個點出逃過 \(j\) 次的最小差異值,易得 \(dp\) 方程為:
\[f_{i,j}=min(f_{k,j-1}+cost_{k+1,i}) \]
其中 \(cost_{l,r}\) 是指:區間 \(l\)
那麼現在需要列舉 \(i\) ,\(j\) ,\(k\) ,\(d\),複雜度為 \(O(n^4)\) ,肯定是不行的,但是我們可以發現在處理略大的 \(d\) 值時其實是可以計算出較小的 \(d\) 值的,所以我們可以直接一起計算,就不需要列舉 \(d\) 了,複雜度就降為 \(O(n^3)\) ,可行了。
程式碼如下:
#include<bits/stdc++.h> using namespace std; const int N=105; int n,a[N]; int cost[N][N],f[N][N]; int main() { cin>>n; for(int i=1;i<=n;++i) scanf("%d",&a[i]); for(int i=1;i<=n;++i) { for(int j=i;j<=n;++j) cost[i][j]=cost[i][j-1]+(a[j]!=j-i); } // for(int i=1;i<=n;++i) // { // for(int j=i;j<=n;++j) // printf("%d %d %d\n",i,j,cost[i][j]); // } memset(f,63,sizeof(f)); for(int i=1;i<=n;++i) { f[i][1]=cost[1][i]; for(int j=1;j<i;++j) { for(int k=1;k<=j;++k) f[i][k+1]=min(f[i][k+1],f[j][k]+cost[j+1][i]); } } for(int i=1;i<=n;++i) printf("%d\n",f[n][i]); return 0; }