集训队作业2018: 通信(区间DP)
题意:
题解:
想到了大概思路就是不会有相交的非链上的边,然而有一堆细节就鸽了。
然后看题解其实就是暂时忽略两边的值来区间DP就行了,设置的状态还挺妙的,中间记个前缀后缀min优化一下,时间复杂度。
#include <bits/stdc++.h>
using namespace std;
#define opt(x) memset(x,0x3f,sizeof(x))
const int N=3e2+5, inf=0x3f3f3f3f;
typedef long long LL;
int n,br[N][N],pr[N][N]; LL a[N];
int f[N][N],g[N][N],gl[N][N],gr[N][N];
vector <int> cov[N][N],fl[N][N],fr[N][N];
vector <int> fl_mn1[N][N],fl_mn2[N][N],fr_mn1[N][N],fr_mn2[N][N];
inline int F(int l,int r);
inline int FL(int l,int p,int s);
inline int FR(int l,int p,int s);
inline int FL_MN1(int l,int p,int s) {
if(p<l) return inf;
int &ret=fl_mn1[l][p][s];
if(ret!=inf) return ret;
return ret=min(FL_MN1(l,p-1,s),FL(l,p,s)+cov[p][s][s]);
}
inline int FL_MN2(int l,int p,int s) {
if(p>s) return inf;
int &ret=fl_mn2[l][p][s];
if(ret!=inf) return ret;
return ret=min(FL_MN2(l,p+1,s),FL(l,p,s));
}
inline int FL(int l,int s,int m) {
int &ret=fl[l][s][m];
if(ret!=inf) return ret;
if(l==s) return F(l,m);
if(s==m) return inf;
ret=min(FL_MN1(l,br[s][m]-1,s),FL_MN2(l,max(l,br[s][m]),s)+cov[s][s][m]);
return ret+=F(s,m),ret;
}
inline int GL(int l,int r) {
if(l==r) return 0;
int &ret=gl[l][r];
if(ret!=inf) return ret;
for(int p=l;p<r;++p)
ret=min(ret,FL(l,p,r)+cov[p][r][r]);
return ret;
}
inline int FR_MN2(int s,int p,int m) {
if(p<s) return inf;
int &ret=fr_mn2[s][p][m];
if(ret!=inf) return ret;
return ret=min(FR_MN2(s,p-1,m),FR(s,p,m));
}
inline int FR_MN1(int s,int p,int m) {
if(p>m) return inf;
int &ret=fr_mn1[s][p][m];
if(ret!=inf) return ret;
return ret=min(FR(s,p,m)+cov[s][s][p],FR_MN1(s,p+1,m));
}
inline int FR(int l,int s,int m) {
if(s==l) return inf;
if(s==m) return F(l,m);
int &ret=fr[l][s][m];
if(ret!=inf) return ret;
ret=min(FR_MN1(s,pr[l][s]+1,m),FR_MN2(s,min(m,pr[l][s]),m)+cov[l][s][s]);
return ret+=F(l,s),ret;
}
inline int GR(int l,int r) {
if(l==r) return 0;
int &ret=gr[l][r];
if(ret!=inf) return ret;
for(int p=l+1;p<=r;++p)
ret=min(ret,FR(l,p,r)+cov[l][l][p]);
return ret;
}
inline int F(int l,int r) {
if(l+1>=r) return 0;
int &ret=f[l][r];
if(ret!=inf) return ret;
for(int m=l;m<r;++m)
ret=min(ret,GL(l,m)+GR(m+1,r));
return ret;
}
inline int G(int l,int r) {
int &ret=g[l][r];
if(ret!=inf) return ret;
if(l==1) return ret=F(l,r)+cov[1][1][r];
for(int p=1;p<l;++p)
ret=min(ret,G(p,l)+F(l,r)+cov[p][l][r]);
return ret;
}
int main() {
opt(f), opt(g), opt(gl), opt(gr);
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++)
for(int j=i-1;j<=n+1;j++) {
cov[i][j].resize(n+1);
fl[i][j].assign(n+1,inf);
fr[i][j].assign(n+1,inf);
fl_mn1[i][j].assign(n+1,inf);
fl_mn2[i][j].assign(n+1,inf);
fr_mn1[i][j].assign(n+1,inf);
fr_mn2[i][j].assign(n+1,inf);
}
for(int i=1;i<=n;i++)
for(int l=1;l<=i;++l)
for(int r=i,R=i,L=l;r<=n;++r) {
while(R+1<=n && a[R+1]-a[i]<=max(a[r]-a[i],a[i]-a[l])) ++R;
while(L-1>=1 && a[i]-a[L-1]<=max(a[r]-a[i],a[i]-a[l])) --L;
cov[l][i][r]=R-L;
}
for(int i=1;i<=n;i++) {
for(int j=1;j<=i;j++)
br[j][i]=lower_bound(a+1,a+j+1,2*a[j]-a[i])-a;
for(int j=i;j<=n;j++)
pr[i][j]=upper_bound(a+j,a+n+1,2*a[j]-a[i])-a-1;
}
int ans=inf;
for(int i=1;i<n;i++)
ans=min(ans,G(i,n)+cov[i][n][n]);
cout<<ans+n<<'\n';
}