1. 程式人生 > 其它 >G. Minimal Coverage(二分)

G. Minimal Coverage(二分)

題目連結

題意:
給定\(n\)條線段,對應長度為\(s_i\),初始所在點為\(0\),按順序進行放置,即在前一點的基礎上進行\(-s_i,+s_i\)操作,求覆蓋區間最短長度。

思路:
二分。
因為線段長度不超過\(1000\),所以覆蓋區間長度不超過\(2000\),在區間\([0,2000]\)二分答案。若最短區間長度為\(k\),無論怎樣操作,覆蓋區間總能移到區間\([0,k]\)內,只是初始所在點不一定為\(0\)

code:

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <deque>
#include <cmath>
#include <ctime>
#include <map>
#include <set>
#include <unordered_map>

#define fi first
#define se second
#define pb push_back
#define endl "\n"
#define debug(x) cout << #x << ":" << x << endl;
#define bug cout << "********" << endl;
#define all(x) x.begin(), x.end()
#define lowbit(x) x & -x
#define fin(x) freopen(x, "r", stdin)
#define fout(x) freopen(x, "w", stdout)
#define ull unsigned long long
#define ll long long 

const double eps = 1e-15;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double pi = acos(-1.0);
const int mod =  1e9 + 7;
const int maxn = 1e4 + 10;

using namespace std;

int n, s[maxn], t;
int dp[maxn][2010];

bool judge(int k){
    for(int i = 0; i <= n; i ++){
        for(int j = 0; j <= 2000; j ++)dp[i][j] = (i == 0 ? 1 : 0);
        //當i=0時,假設初始點在j
    }
    for(int i = 1; i <= n; i ++){
        for(int j = 0; j <= k; j ++){
            if(dp[i - 1][j] && j + s[i] <= k)dp[i][j + s[i]] = 1;
            if(dp[i - 1][j] && j - s[i] >= 0)dp[i][j - s[i]] = 1;
        }
    }
    for(int i = 0; i <= k; i ++)if(dp[n][i])return true;
    return false;
}

void solve(){
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++)scanf("%d", &s[i]);

    int l = 0, r = 2000;
    while(l < r){
        int mid = l + r >> 1;
        if(judge(mid))r = mid;
        else l = mid + 1;
    }
    printf("%d\n", l);
}

int main(){
    scanf("%d", &t);
    while(t --)solve();
    return 0;
}

此題還可以用dp做(dp太菜了wwwwwww)