Silver: Range Reconstruction

[P8902 USACO22DEC] Range Reconstruction S - 洛谷

这道构造题只要想清楚其实还是比较好做的。(但是如果没想出来就容易绷不住).对于任何的一个​a[i],它都可以是: ​diff[i-1][1]\pm a[i-1]的。所以现在的问题就是,我们如何确定是​+还是​-

对于这个问题, 如果用暴力,就是​O(2^N), 非常爆炸。

我们可以考虑从后往前推:先选取+的情况,然后检测是否有效。如果无效,就选择-。关键的问题是如何检测是否有效

4
0 1 1 2
0 0 2
0 2
0

首先,在测试样例#4 中,我们可以发现:如果我们从后往前推(a[n-1]->a[0]),可以在每一个i都都选用之前的范围,也就是diff[i][0N-i],对a[iN]中的max-min进行检验。以下是核心代码:

// given that at position i:
int current_max=INT_MIN;
int current_min=INT_MAX;
for(int j=i;j<n;j++){
    current_max=max(current_max,a[j]);
    current_min=min(current_min,a[j]);
    if(current_max-current_min!=diff[i][j-i]){'
        // invalid
    }
}
// valid for every case

通过这个步骤,我们就可以从后往前推了

//
// Created by Chixiyu on 12/3/2023.
// Range reconstruction s (construction)

#include <bits/stdc++.h>
using namespace std;

int main(){
    //input
    int n;
    cin>>n;
    int** diff=new int*[n];
    for(int i=0;i<n;i++){
        diff[i]=new int[n];
    }
    vector<int> a(n,0);
    for(int i=0;i<n;i++){
        for(int j=0;j<n-i;j++){
            cin>>diff[i][j];
        }
    }

    for(int i=n-2;i>=0;i--){// inverse iteration
        auto check=[&]()->bool{
            int mx=INT_MIN;
            int mn=INT_MAX;
            for(int j=i;j<n;j++) {
                mx=max(mx,a[j]);
                mn=min(mn,a[j]);
                if((mx-mn)!=diff[i][j-i]){
                    return false;

                }
            }
            return true;
        };
        // 1. put it in to check if valid
        a[i]=a[i+1]+diff[i][1];
        if(!check())// not valid
            a[i]=a[i+1]-diff[i][1];// the other way round
    }
    for (const auto &item: a) {
        cout<<item<<' ';
    }
}