cnblogs
题面
第二道根号分治,对初学者来说很友好的一道题。
题意在题面中写的很清楚,这里不多赘述。
思路
先从暴力开始想。
每次暴力的时间复杂度最坏明显是 \(O(n^2)\) 的,因为是类似区间加和最后统计的问题,可以尝试用差分来做。
但普通差分需要枚举 \(d\) 的大小,复杂度仍然是 \(O(n^2)\)。
观察到每次暴力时,\(d\) 与枚举的次数成反比,也就是 \(d\) 越大枚举的次数越少。至此,我们可以使用根号分治解决。
设阈值为 \(B\),则暴力复杂度为 \(O(\frac{n}{B})\),差分复杂度为 \(O(nB)\),折中取 \(B=\sqrt{n}\),总复杂度即为 \(O(n\sqrt{n})\)。
不过差分数组开 \(n\sqrt{n}\) 的空间是会 MLE 的,因此阈值也要向下调整一些,以及一些小的空间问题,建议前往讨论区。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10,M=2e2+10;
int n,m;
int B;
int a[N];
int f[N][M];
int main(){cin>>n>>m;B=sqrt(n)/2;for(int i=1;i<=m;i++){int x,l,d;cin>>x>>l>>d;if(d<=B){f[x][d]++;f[x+l*d][d]--;}else{for(int j=0;j<l;j++){a[x+j*d]++;}}}for(int j=1;j<=B;j++){for(int i=1;i<=n;i++){if(i>=j) f[i][j]+=f[i-j][j];a[i]+=f[i][j];}}for(int i=1;i<=n;i++){cout<<a[i]<<' ';}return 0;
}