codeforces 1579G Codeforces Round #744 (Div. 3)

题意:

按顺序给定n条线段,从0开始,可以正放也可以反放(+x,-x),问n条放完之后最小覆盖区间长度。

思路:

很容易可以想到对于一个左端点找一个最左的右端点,但是如果是确定的左右坐标,我们会无法知道当前的位置,然后无法进行转移。

又考虑到左右端点和当前位置的具体坐标其实不需要知道,我们只需要一个距离也就是相对长度。

所以不妨把左右端点以及当前位置进行相对位置的记录。

那么原本的dp[i][j]表示第i条的左端点的最优右端点变成了dp[i][j]表示第i条距离左端点的相对位置为j时右端点的最优解。

当j<a[i]时,说明此时-a[i]会移动左端点,那么相对距离变成0,移左相当于移右。

其余情况正常转移。

而且值域必定在2000以内。

下附代码:

#include<bits/stdc++.h>
using namespace std;
const int INF=0X3f3f3f3f;
int dp[10005][2005];
int main(){
    int T;
    scanf("%d",&T);
    while (T--){
        int n;
        scanf("%d",&n);
        for (int i=0; i<=n; i++){
            for (int j=0; j<=2000; j++){
                dp[i][j]=INF;
            }
        }
        dp[0][0]=0;
        for (int i=1; i<=n; i++){
            int x;
            scanf("%d",&x);
            for (int j=0; j<=2000; j++){
                if (dp[i-1][j]!=INF){
                    if (j<x){
                        dp[i][0]=min(dp[i][0],dp[i-1][j]+(x-j));
                    }
                    else {
                        dp[i][j-x]=min(dp[i][j-x],dp[i-1][j]);
                    }
                    if (j+x<=2000) dp[i][j+x]=min(dp[i][j+x],max(dp[i-1][j],j+x));
                }
            }
        }
        int res=INF;
        for (int i=0; i<=2000; i++){
            res=min(res,dp[n][i]);
        }
        printf("%d\n",res);
    }
}
/*10
5 6 7 3 3 1 3 5 4 6
*/
View Code

 

posted @ 2021-09-29 20:30  我是菜狗QAQ  阅读(110)  评论(0编辑  收藏  举报