package class38; // 360笔试题 // 长城守卫军 // 题目描述: // 长城上有连成一排的n个烽火台,每个烽火台都有士兵驻守。 // 第i个烽火台驻守着ai个士兵,相邻峰火台的距离为1。另外,有m位将军, // 每位将军可以驻守一个峰火台,每个烽火台可以有多个将军驻守, // 将军可以影响所有距离他驻守的峰火台小于等于x的烽火台。 // 每个烽火台的基础战斗力为士兵数,另外,每个能影响此烽火台的将军都能使这个烽火台的战斗力提升k。 // 长城的战斗力为所有烽火台的战斗力的最小值。 // 请问长城的最大战斗力可以是多少? // 输入描述 // 第一行四个正整数n,m,x,k(1<=x<=n<=10^5,0<=m<=10^5,1<=k<=10^5) // 第二行n个整数ai(0<=ai<=10^5) // 输出描述 仅一行,一个整数,表示长城的最大战斗力 // 样例输入 // 5 2 1 2 // 4 4 2 4 4 // 样例输出 // 6 public class Code02_GreatWall { public static int maxForce(int[] wall, int m, int x, int k) { long L = 0; long R = 0; for (int num : wall) { R = Math.max(R, num); } R += m * k; long ans = 0; while (L <= R) { long M = (L + R) / 2; if (can(wall, m, x, k, M)) { ans = M; L = M + 1; } else { R = M - 1; } } return (int) ans; } public static boolean can(int[] wall, int m, int x, int k, long limit) { int N = wall.length; // 注意:下标从1开始 SegmentTree st = new SegmentTree(wall); st.build(1, N, 1); int need = 0; for (int i = 0; i < N; i++) { // 注意:下标从1开始 long cur = st.query(i + 1, i + 1, 1, N, 1); if (cur < limit) { int add = (int) ((limit - cur + k - 1) / k); need += add; if (need > m) { return false; } st.add(i + 1, Math.min(i + x, N), add * k, 1, N, 1); } } return true; } public static class SegmentTree { private int MAXN; private int[] arr; private int[] sum; private int[] lazy; private int[] change; private boolean[] update; public SegmentTree(int[] origin) { MAXN = origin.length + 1; arr = new int[MAXN]; for (int i = 1; i < MAXN; i++) { arr[i] = origin[i - 1]; } sum = new int[MAXN << 2]; lazy = new int[MAXN << 2]; change = new int[MAXN << 2]; update = new boolean[MAXN << 2]; } private void pushUp(int rt) { sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; } private void pushDown(int rt, int ln, int rn) { if (update[rt]) { update[rt << 1] = true; update[rt << 1 | 1] = true; change[rt << 1] = change[rt]; change[rt << 1 | 1] = change[rt]; lazy[rt << 1] = 0; lazy[rt << 1 | 1] = 0; sum[rt << 1] = change[rt] * ln; sum[rt << 1 | 1] = change[rt] * rn; update[rt] = false; } if (lazy[rt] != 0) { lazy[rt << 1] += lazy[rt]; sum[rt << 1] += lazy[rt] * ln; lazy[rt << 1 | 1] += lazy[rt]; sum[rt << 1 | 1] += lazy[rt] * rn; lazy[rt] = 0; } } public void build(int l, int r, int rt) { if (l == r) { sum[rt] = arr[l]; return; } int mid = (l + r) >> 1; build(l, mid, rt << 1); build(mid + 1, r, rt << 1 | 1); pushUp(rt); } public void update(int L, int R, int C, int l, int r, int rt) { if (L <= l && r <= R) { update[rt] = true; change[rt] = C; sum[rt] = C * (r - l + 1); lazy[rt] = 0; return; } int mid = (l + r) >> 1; pushDown(rt, mid - l + 1, r - mid); if (L <= mid) { update(L, R, C, l, mid, rt << 1); } if (R > mid) { update(L, R, C, mid + 1, r, rt << 1 | 1); } pushUp(rt); } public void add(int L, int R, int C, int l, int r, int rt) { if (L <= l && r <= R) { sum[rt] += C * (r - l + 1); lazy[rt] += C; return; } int mid = (l + r) >> 1; pushDown(rt, mid - l + 1, r - mid); if (L <= mid) { add(L, R, C, l, mid, rt << 1); } if (R > mid) { add(L, R, C, mid + 1, r, rt << 1 | 1); } pushUp(rt); } public long query(int L, int R, int l, int r, int rt) { if (L <= l && r <= R) { return sum[rt]; } int mid = (l + r) >> 1; pushDown(rt, mid - l + 1, r - mid); long ans = 0; if (L <= mid) { ans += query(L, R, l, mid, rt << 1); } if (R > mid) { ans += query(L, R, mid + 1, r, rt << 1 | 1); } return ans; } } public static void main(String[] args) { int[] wall = { 3, 1, 1, 1, 3 }; int m = 2; int x = 3; int k = 1; System.out.println(maxForce(wall, m, x, k)); } }