Fluctuation Limit ——hdu多校第八场

链接:http://acm.hdu.edu.cn/showproblem.php?pid=6860.
来源:杭电多校第八场

题目描述

给你n个范围[li,ri]和一个整数x,要求构建一个长度为n的数组ai,要求保证ai >= li && ai <= ri,并且保证相邻两个x之间的差值的绝对值不大于x

分析

这道题构建的数组要求满足两个条件,要求在相应的区间内,并且和上一个数字的差值绝对值小于等于x

我们可以这样考虑,如果第一个数字我们选择了a,那么第二个数字选择的范围就是a + x ~ a - x之间,这个范围内的每一个数字都是合法的,那什么状态是非法的呢,就是我们得出的这个区间和给定的范围区间的交集为空,那么我就无法找到任何一个数字满足这两个条件

所以,我们可以根据给定的第一个区间,推断第二个区间满足第二个条件的范围,也就是[l1 - x, r1 + x],然后再让这个区间和[l2,r2]区间取并集,那么得到的区间中的任何一个数字都是合法区间

所以,我们可以确定2 - n的合法区间,但1的合法区间我们无法判断,我们只知道第二段的合法区间内的每一个数字都可以由1区间的一个数字转移过来,但我们并不知道第一段中的那些数字可以转化为第二段的合法数字,所以我们选择从第n段区间内任取一个数字,根据刚才的操作我们知道我们可以从第n - 1区间内找到一个符合要求的数字,然后以此类推,一直往前推即可

代码

#include <iostream>

using namespace std;

const int N = 1e5 + 10;
int a[N],b[N];
int ans[N];
int st,en;
int n,x;

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&x);
        scanf("%d%d",&st,&en);
        a[1] = st,b[1] = en;
        int flag = 1;
        for(int i = 2;i <= n;i++){
            int p,q;
            scanf("%d%d",&p,&q);
            if(!flag) continue;
            int s = st - x,e = en + x;
            if(s > q || e < p) flag = 0;
            else{ 
                st = max(p,s);  //取并集,确定合法区间
                en = min(e,q);
            }
            a[i] = st,b[i] = en;
        }
        if(!flag){
            puts("NO");
            continue;
        }
        puts("YES");
        ans[n] = a[n];  //取最后一段合法区间的左端点
        for(int i = n - 1;i >= 1;i--){
            if(ans[i + 1] >= a[i] && ans[i + 1] <= b[i]){ //上一个答案位于区间内部
                ans[i] = ans[i + 1];
                continue;
            }
            if(ans[i + 1] + x >= a[i] && ans[i + 1] + x <= b[i]){ //上一个答案位于区间左边
                ans[i] = a[i];
                continue;
            }
            ans[i] = b[i]; //上一个答案位于区间右边
        }
        for(int i =1;i < n;i++) printf("%d ",ans[i]);
        printf("%d\n",ans[n]);
    }
}


猜你喜欢

转载自blog.csdn.net/tlyzxc/article/details/107990272