bzoj 1742: [Usaco2005 nov]Grazing on the Run 邊跑邊吃草【區間dp】
阿新 • • 發佈:2018-09-01
sin can 開始 code \n 所有 class i++ scan
挺好的區間dp,狀態設計很好玩
一開始按套路設f[i][j],g[i][j]為吃完(i,j)區間站在i/j的最小腐敗值,後來發現這樣並不能保證最優
實際上是設f[i][j],g[i][j]為從i開始吃j個,站在這段區間的左/右端點的 * 最小所有草增加的腐敗值 * ,因為這些腐敗之最後也是要算進去的,所以直接夾在裏面就可以保證最優
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=1005; long long n,m,l,r,f[N][2],g[N][2],a[N]; int main() { scanf("%lld%lld",&n,&m); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); sort(a+1,a+n+1); for(int i=1;i<=n;i++) { if(a[i]<=m) l=i; if(!r&&a[i]>m) r=i; } memset(f,0x3f,sizeof(f)); memset(g,0x3f,sizeof(g)); if(l) f[l][1]=g[l][1]=n*(m-a[l]); if(r) f[r][1]=g[r][1]=n*(a[r]-m); for(int k=2;k<=n;k++) for(int i=1;i+k-1<=n;i++) { int j=i+k-1; f[i][k&1]=min(f[i+1][~k&1]+(n-k+1)*(a[i+1]-a[i]),g[i+1][~k&1]+(n-k+1)*(a[j]-a[i])); g[i][k&1]=min(g[i][~k&1]+(n-k+1)*(a[j]-a[j-1]),f[i][~k&1]+(n-k+1)*(a[j]-a[i])); } printf("%lld\n",min(f[1][n&1],g[1][n&1])); return 0; }
bzoj 1742: [Usaco2005 nov]Grazing on the Run 邊跑邊吃草【區間dp】