题解 CF1579G Minimal Coverage

CF1579G Minimal Coverage

dp好题! link to the problem

解法

首先需要观察到:如果最长线段的长度为\(maxL\),那么答案不可能超过\(2maxL\) 。

证明的话,可以用构选法来说明:当处于当前线段的尾处于区间\([0,maxL]\)时,下一个线段向右延伸;反之,当当前线段的尾处于区间\([maxL+1,2maxL]\)的话,那么下一个线段就向左延伸。由于\(maxL\)就是所有线段长度的最大值,因此不会有线段横跨\([0,maxL]\)或\([maxL+1,2maxL]\)

设 \(dp_{i,j}\)表示:第\(i\)个线段的结尾与整个覆盖区间左端点的距离为\(j\)时,该结尾与覆盖区间右端点的最小距离 \稍微有点绕

题解 CF1579G Minimal Coverage

由于观察出来的结论,\(j\)只需要讨论\([0,2maxL]\)即可。

若第\(i\)个线段向左移动:\(dp_{i,max(0,j-a_i)\leftarrow dp_{i-1,j}+a_i}\)

若第\(i\)个线段向右移动:\(dp_{i,j+a_i}\leftarrow max(dp_{i-1,j}-a_i,0)\)

最后在统计答案时,答案就是\(\min_{i=0}^{2maxL}{i+dp_{n,i}}\)

代码

#include <bits/stdc++.h>
using namespace std;
#define lor(a,b,c) for(register int a=b;a<=c;++a)
#define ror(a,b,c) for(register int a=c;a>=b;--a)

const int N=1e4+5,M=2005,INF=0x3f3f3f3f;

int n,a[N],dp[N][M],maxlen,ans;

inline void updata(int &a,int b) {a=min(a,b);}

int main(){
	#ifndef ONLINE_JUDGE
	freopen("test.in","r",stdin);
	#endif

	int qwq; for(scanf("%d",&qwq);qwq;qwq--){
		scanf("%d",&n); lor(i,1,n) scanf("%d",a+i);
		maxlen=0; lor(i,1,n) maxlen=max(maxlen,a[i]);
		lor(i,0,n) lor(j,0,maxlen*2) dp[i][j]=INF; dp[0][0]=0;
		lor(i,1,n){
			lor(L,0,maxlen*2) if(dp[i-1][L]^INF){
				updata(dp[i][max(0,L-a[i])],dp[i-1][L]+a[i]);
			}
			lor(L,0,maxlen*2-a[i]) if(dp[i-1][L]^INF){
				updata(dp[i][L+a[i]],max(dp[i-1][L]-a[i],0));
			}
		}
		ans=INF; lor(i,0,maxlen) updata(ans,i+dp[n][i]);
		printf("%d\n",ans);
	}

	return 0;
}
上一篇:Kruskal维护连通块个数


下一篇:CF1579G Minimal Coverage