BZOJ 2412: 电路检修
Description
[0,x]中全是1,其余全是0,每个点有一个权值,求最坏情况下得到x的最小权值.
Sol
DP+单调队列.
你可以去看我的这篇Blog...开这篇纯属为了骗访问...
http://www.cnblogs.com/beiyuoi/p/5974574.html
Code
/************************************************************** Problem: 2448 User: BeiYu Language: C++ Result: Accepted Time:1316 ms Memory:48420 kb ****************************************************************/ #include<cstdio> #include<iostream> using namespace std; const int N = 2005; #define A(x) (f[i][x-1]+a[x]) #define B(x) (f[x+1][j]+a[x]) int n,a[N]; int f[N][N],g[N][N]; int q[N][N],h[N],t[N]; inline int in(int x=0,char ch=getchar(),int v=1){ while(ch!='-' && (ch>'9'||ch<'0')) ch=getchar();if(ch=='-') v=-1,ch=getchar(); while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*v; } int main(){ // freopen("in.in","r",stdin); n=in(); for(int i=1;i<=n;i++) a[i]=in(); for(int i=n;i;--i){ f[i][i]=a[i],g[i][i]=i; //f[i][j]=min{ f[i][k-1]+t[k] },g[i][j]<=k<=j; =>q[0] //f[i][j]=min{ f[k+1][j]+t[k] },i<=k<g[i][j]; =>q[j] h[0]=1,t[0]=0; h[i]=1,t[i]=0; q[i][++t[i]]=i; for(int j=i+1;j<=n;++j){ //g[i][j] g[i][j]=g[i][j-1]; while(g[i][j]<j && f[i][g[i][j]-1] < f[g[i][j]+1][j]) ++g[i][j]; //q[0].pop g[i][j-1]--(g[i][j]-1) for(int k=g[i][j-1];k<g[i][j];++k) if(q[0][h[0]] == k) ++h[0]; //j->q[0] while(h[0]<=t[0] && A(q[0][t[0]]) > A(j)) --t[0]; q[0][++t[0]]=j; //q[j].pop g[i+1][j]-g[i][j] for(int k=g[i+1][j];k>=g[i][j];--k) if(q[j][h[j]] == k) ++h[j]; //i->q[j] while(h[j]<=t[j] && B(q[j][t[j]]) > B(i)) --t[j]; q[j][++t[j]]=i; //f[i][j] f[i][j]=min(A(q[0][h[0]]),B(q[j][h[j]])); } } // for(int i=1;i<=n;i++) for(int j=1;j<=n-i+1;j++) printf("%d%c",g[j][j+i-1]," \n"[j==n-i+1]); // cout<<"***"<<endl; // for(int i=1;i<=n;i++) for(int j=1;j<=n-i+1;j++) printf("%d%c",f[j][j+i-1]," \n"[j==n-i+1]); cout<<f[1][n]<<endl; return 0; }