https://codeforces.com/contest/1954/problem/E
题意:n个数,可以对每个数释放闪电,闪电从释放的位置一直传到左右边界或者传到某个小于等于0的数终止,并且每个数都会减去闪电值k。问最少多少次释放闪电后可以让所有的数小于等于0。
思路:从左往右考虑,假设第一个数的权值为1,如果当前数>前一个数,那么权值+1。如果前一个数小于当前数,前一个数的权值-1。最后求出来每个强度的数一个权值。(i - k + 1) / k * weight[i],就是所有数值为i的数变成0需要电机的次数。 可以求一个前缀和分块计算,降低时间复杂度。
总结:没写过这种题型,感觉比较难理解,最后还有个类似分块的思想。分块:给个左端点,可以知道右端点,在这个左右端点的区间内,所有数的计算方式都一样,可以把他们按同样的方式处理,避免了一个一个处理,降低计算次数。
void solve(){
int n;
cin >> n;
vector<int> a(n);
for (auto& x : a){
cin >> x;
}
int m = *max_element(a.begin(), a.end());
vector<int> b(m + 1);
b[a[0]] ++;
for (int i = 1; i < n; ++i){
if (a[i] > a[i - 1]){
b[a[i]] ++;
}
if (a[i - 1] < a[i]){
b[a[i - 1]] --;
}
}
for (int i = 1; i <= m; ++i){
b[i] += b[i - 1];
}
for (int k = 1; k <= m; ++k){
long long ans = 0;
for (int i = 1; i <= m; i += k){
ans += 1ll * (i + k - 1) / k * (b[min(i + k - 1, m)] - b[i - 1]);
}
cout << ans << " \n"[k == m];
}
}
标签:Reaction,Chain,分块,int,闪电,++,端点,权值
From: https://www.cnblogs.com/yxcblogs/p/18159252