题目大意:给一个长度为n的数列,划分成多个部分,每一个部分长度要大于等于K,定义每个部分的质量差是这部分的最大值减去最小值,求最优划分后,全局的质量差最小是多少。
题目分析:二分答案,check
dp来check,dp[i] 代表 i这个位置可以作为一个区间的结尾,如果 i - 1 可以作为结尾, 那么就可以更新 i 作为开头的结尾位置, [l,r] 区间dp值赋为1,线段树,check dp[n]是否唯一。
1 #include<bits/stdc++.h> 2 #define lson l, m, rt << 1 3 #define rson m + 1, r, rt << 1 | 1 4 #define maxn 300010 5 using namespace std; 6 int a[maxn], n, k; 7 bool vis[maxn << 2], lazy[maxn << 2]; 8 void build(int l,int r,int rt){ 9 vis[rt] = false, lazy[rt] = false; 10 if(l == r){ 11 return; 12 } 13 int m = (l + r) >> 1; 14 build(lson); 15 build(rson); 16 } 17 void pushdown(int rt){ 18 if(lazy[rt]){ 19 lazy[rt << 1] = true; 20 lazy[rt << 1 | 1] = true; 21 vis[rt << 1] = true; 22 vis[rt << 1 | 1] = true; 23 lazy[rt] = false; 24 return; 25 } 26 } 27 void update(int L,int R,int l,int r,int rt){ 28 if(L <= l && R >= r){ 29 vis[rt] = true; 30 lazy[rt] = true; 31 return; 32 } 33 pushdown(rt); 34 int m = (l + r) >> 1; 35 if(L <= m) 36 update(L, R, lson); 37 if(R > m) 38 update(L, R, rson); 39 } 40 bool query(int pos,int l,int r,int rt){ 41 if(l == r) return vis[rt]; 42 pushdown(rt); 43 int m = (l + r) >> 1; 44 if(pos <= l) return query(pos,lson); 45 else return query(pos, rson); 46 } 47 bool ok(int x){ 48 int now, step, p, cur; 49 p = 1; 50 build(1,n,1); 51 for(int i = 1; i < n; i ++){ 52 now = upper_bound(a + 1, a + 1 + n, a[i] + x) - a; 53 now --; 54 cur = i + k - 1; 55 if(cur <= now && (i == 1 || query(i - 1, 1, n, 1))){ 56 update(cur, now, 1, n, 1); 57 } 58 } 59 return query(n,1,n,1); 60 } 61 int main(){ 62 cin >> n >> k; 63 for(int i = 1; i <= n; i ++) cin >> a[i]; 64 sort(a + 1, a + 1 + n); 65 int l = 0, r = 1000000000, mid, res; 66 while(l <= r){ 67 mid = (l + r) >> 1; 68 if(ok(mid)){ 69 r = mid - 1; 70 res = mid; 71 } 72 else 73 l = mid + 1; 74 } 75 cout << res; 76 return 0; 77 }