CF1954E Chain Reaction
正在写数论分块,发现这道题竟然是向上取整的数论分块,我直接就去写了。
题意概括
有 \(n\) 个怪兽,对于一个伤害 \(k\),每一次会对一段连续的存活的怪物打出 \(k\) 的伤害,对于一堆 \(k\) 求出每一个 \(k\) 的最小攻击次数。
我们先考虑一下对于一个 \(k\) 而言,它的答案是什么。
可以算每一对相邻的贡献是多少,看得出来就是 \(max(0,ceil(\frac{a_i}{k})-ceil(\frac{a_{i-1}}{k}))\)。
整体就是 \(\sum_{i=1}^{n}max(0,ceil(\frac{a_i}{k})-ceil(\frac{a_{i-1}}{k}))\)
这个显然是数论分块可求的。
热知识:对于 \(ceil(\frac{n}{l})\),对应的右端点是 \(floor(\frac{n-1}{floor(\frac{n-1}{l})})\)。
我们感觉会做了,但是我们发现似乎没有什么好的办法清空每一次,写数据结构太麻烦,而且这个题似乎卡常?反正多了一个 log 是绝对不可能过的。
所以我们便采取新的策略,计算每一对相邻的点对于所有 \(k\) 的贡献。
我们使用差分,做数论分块就行了。
注意这个题卡常,define int long long 会 T。
代码。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
namespace BaiBaiShaFeng{
const int MN=3e5+315;
int n, a[MN], maxn=0;
long long d[MN];
void update(int l, int r, int val){
if(val<0) return;
d[l]+=val; d[r+1]-=val;
}
void solve(){
cin>>n; d[0]=1;
for(int i=1; i<=n; ++i) cin>>a[i];
for(int i=1; i<=n; ++i) maxn=max(maxn,a[i]);
for(int i=1; i<=n; ++i){
int vala=a[i], valb=a[i-1];
for(int l=1, r; l<=maxn; l=r+1){
int mra, mrb;
if(l>=vala) mra=maxn+1;
else mra=((vala-1)/((vala-1)/l));
if(l>=valb) mrb=maxn+1;
else mrb=((valb-1)/((valb-1)/l));
r=min(mra,mrb);
if(r==maxn+1) break;
update(l,r,(vala-1)/l-max((int)0,valb-1)/l);
}
}
for(int i=1; i<=maxn; ++i) d[i]+=d[i-1];
for(int i=1; i<=maxn; ++i) cout<<d[i]<<" ";
}
}
signed main(){
//ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
BaiBaiShaFeng::solve();
return 0;
}

浙公网安备 33010602011771号