E. Chain Reaction:
题目描述:
思路解析:
向怪物发送k伤害的闪电打击,但是攻击只在活着的怪物中传播,假如 a b c d e,b和d怪物死了,如果攻击任意活着的怪物那么只有它自己受到伤害。那么可以容易想到血量低的怪物,一定会把左右两边的怪物分为两块。
那么我们可以直接非递减序列看为一块区域。那么多块区域怎么计算答案。
例如这个样例:怪物可分为 (1 9) (7) (6) (2 4 7 8) (1 3) 的区域块,对于 k 的连锁闪电。
对于每个区域块,如果区域中血量最高的死掉了,那么整个区域块就全部死掉,所以需要的代价就是杀死血量最高的怪物。 两个区域块之间,可以共享的伤害就是下一个区域块中第一个怪物能够承受的伤害,在答案中需要减去这部分代价。
但是这样对每一个k暴力求答案的时间复杂度是趋近于 O(n*n),那么想怎么优化,我们可以发现对于9来说, 当k=1--1时提供9的贡献,当k=2--2时提供5的贡献,当k=3--4时提供3的贡献,当k=5--8时提供2的贡献,可以发现计算答案贡献时,其实有部分长的区间贡献是相同的,所以我们可以利用差分数组,来计算区间段的贡献。
代码实现:
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
int t = 1;
while (t > 0) {
solve();
t--;
}
w.flush();
w.close();
}
static int mod = 998244353;
public static void solve() throws IOException{
int n = f.nextInt();
int[] a = new int[n];
int mx = 0;
int pre = -1;
LinkedList<Node> list = new LinkedList<>();
int min = a[0];
for (int i = 0; i < n; i++) {
a[i] = f.nextInt();
mx = Math.max(mx, a[i]);
if (a[i] >= pre){
pre = a[i];
}else {
list.add(new Node(min, pre));
min = a[i];
pre = a[i];
}
}
list.add(new Node(min, pre));
long[] suf = new long[mx+5];
pre = -1;
for (Node node : list) {
suf[node.max+1]++;
int r = node.max;
while (r > 0){
int val = (node.max + r - 1) / r;
int l = (node.max + val - 1) / val;
suf[l] += val;
suf[r+1] -= val;
r = l - 1;
}
if (pre != -1){
suf[node.min+1]--;
r = node.min;
while (r > 0){
int val = (node.min + r - 1) / r;
int l = (node.min + val - 1) / val;
suf[l] -= val;
suf[r+1] += val;
r = l - 1;
}
}
pre = 0;
}
for (int i = 1; i <= mx; i++) {
suf[i] += suf[i-1];
w.print(suf[i] + " ");
}
}
public static class Node{
int min, max;
public Node(int min, int max) {
this.min = min;
this.max = max;
}
}
static PrintWriter w = new PrintWriter(new OutputStreamWriter(System.out));
static Input f = new Input(System.in);
static class Input {
public BufferedReader reader;
public StringTokenizer tokenizer;
public Input(InputStream stream) {
reader = new BufferedReader(new InputStreamReader(stream), 32768);
tokenizer = null;
}
public String next() throws IOException{
while (tokenizer == null || !tokenizer.hasMoreTokens()) {
tokenizer = new StringTokenizer(reader.readLine());
}
return tokenizer.nextToken();
}
public int nextInt() throws IOException {
return Integer.parseInt(next());
}
public long nextLong() throws IOException {
return Long.parseLong(next());
}
public Double nextDouble() throws IOException {
return Double.parseDouble(next());
}
}
}