集训队作业2018: 通信(区间DP)

题意:

题解:
想到了大概思路就是不会有相交的非链上的边,然而有一堆细节就鸽了。

然后看题解其实就是暂时忽略两边的值来区间DP就行了,设置的状态还挺妙的,中间记个前缀后缀min优化一下,时间复杂度 O ( n 3 ) O(n^3)

#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';
}
发布了553 篇原创文章 · 获赞 227 · 访问量 24万+

猜你喜欢

转载自blog.csdn.net/qq_35649707/article/details/84563191