G. Minimal Coverage(二分)
阿新 • • 發佈:2021-10-01
題意:
給定\(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)