CF1553F Pairwise Modulo 题解
Link.
Description.
对每个 \(k\) 求
\[\sum_{i=1}^k\sum_{j=1}^ka_i\ \text{mod}\ a_j
\]
Solution.
因为这个相当于是求一个前缀的权值,所以我们考虑一个一个插入元素。
考虑插入一个元素后多出来了什么,显然多出来了两部分。
\[\left(\sum_{j=1}^{i-1}a_j\ \text{mod}\ a_i\right)+\left(\sum_{j=1}^ia_i\ \text{mod}\ a_j\right)
\]
由于 \(a_i\ \text{mod}\ a_j=0\),所以重复的那个可以不需要考虑。
然后根据经典套路,考虑把 \(x\ \text{mod}\ y\) 变成 \(x-y\times\left\lfloor\frac xy\right\rfloor\)。
然后带入式子后发现,式子变成了
\[\begin{aligned}
\left(\sum_{j=1}^{i-1}a_j\right)-\left(\sum_{j=1}^{i-1}{\left\lfloor\frac{a_j}{a_i}\right\rfloor}\times a_j\right)+\left(a_i\times (i-1)\right)-\left(\sum_{j=1}^{i-1}\left\lfloor\frac{a_i}{a_j}\times a_j\right\rfloor\right)
\end{aligned}
\]
接下来就考虑如何算式子了。
第一部分和第三部分就不说了,直接求和有手就行。
然后第二部分就是一个根号分治,小于根号开桶,大于根号暴算,复杂度 \(O(n\times\sqrt v)\)。
然后第四部分就直接一个整除分块,然后用一个数据结构维护前缀和。
注意查询有 \(O(n\times\sqrt v)\) 次,而修改只有 \(O(n)\) 次,如果用树状树组等 \(O(\log)-O(\log)\) 的数据结构复杂度不平衡。
可以考虑值域分块,复杂度 \(O(\sqrt v)-O(1)\),这样复杂度平衡,可以优化掉一个 \(\log\)。
然后这题就做完了,我也不知道为什么昨晚降智不会做。
Coding.
点击查看不行代码
//是啊……你就是那只鬼了……所以被你碰到以后,就轮到我变成鬼了{{{
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
x=0;char c=getchar(),f=0;
for(;c<'0'||c>'9';c=getchar()) if(c=='-') f=1;
for(;c>='0'&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
if(f) x=-x;
}/*}}}*/
const int N=300000,B=550,blt=N/B+5;
int n,cb[blt+5],ca[N+5];ll sb[blt+5],sa[N+5],vl[blt+5],res=0;
inline int qryc(int x) {x=min(x,N);return cb[(x-1)/B+1]+ca[x];}
inline ll qrys(int x) {return sb[(x-1)/B+1]+sa[x];}
inline void modif(int x)
{
int wh=(x-1)/B+1;for(int i=wh+1;i<=blt;i++) cb[i]++,sb[i]+=x;
for(int i=x;i<=min(N,wh*B);i++) ca[i]++,sa[i]+=x;
for(int i=1;i<=B;i++) vl[i]+=x/i;
}
int main()
{
read(n);for(int i=1,x;i<=n;printf("%lld ",res),modif(x),i++)
{
read(x),res+=1ll*(i-1)*x;//ai mod ? = ai * x - \sum ai / ? * ?
for(int l=1,r;l<=x;l=r+1) r=x/(x/l),res-=1ll*(qrys(r)-qrys(l-1))*(x/l);
res+=qrys(N);if(x<=B) res-=vl[x]*x;else//? mod ai
for(int i=x;i<=N;i+=x) res-=1ll*i*(qryc(i+x-1)-qryc(i-1));
}
return putchar('\n'),0;
}