F. Pairwise Modulo
想到了,但又没完全想到。。wtcl
首先 pk=pk−1+∑1≤i<kakmodai+∑1≤i<kaimodakp_k=p_{k-1}+\sum_{1\leq i<k} a_k \bmod \ a_i+\sum_{1\leq i<k} a_i \bmod \ a_kpk=pk−1+∑1≤i<kakmod ai+∑1≤i<kaimod ak
∑1≤i<kakmodai=∑1≤i<k(ak−⌊akai⌋ai)=(k−1)ak−s\sum_{1\leq i<k} a_k\bmod a_i=\sum_{1\leq i<k}(a_k- \left \lfloor \frac{a_k}{a_i} \right \rfloor a_i)=(k-1)a_k-s∑1≤i<kakmodai=∑1≤i<k(ak−⌊aiak⌋ai)=(k−1)ak−s
考虑如何计算s=∑1≤i<k⌊akai⌋ais=\sum_{1\leq i<k}\left \lfloor \frac{a_k}{a_i} \right \rfloor a_is=∑1≤i<k⌊aiak⌋ai
如果kai≤ak<(k+1)aika_i\leq a_k<(k+1)a_ikai≤ak<(k+1)ai那么⌊akai⌋ai=kai\left \lfloor \frac{a_k}{a_i} \right \rfloor a_i=ka_i⌊aiak⌋ai=kai,这个东西用树状数组维护一下,不太容易描述,详细看代码。
∑1≤i<kaimodak=∑1≤i<k(ai−⌊aiak⌋ak)=∑1≤i<kai−t\sum_{1\leq i<k} a_i \bmod a_k=\sum_{1\leq i<k}(a_i- \left \lfloor \frac{a_i}{a_k} \right \rfloor a_k)=\sum_{1\leq i<k}a_i-t∑1≤i<kaimodak=∑1≤i<k(ai−⌊akai⌋ak)=∑1≤i<kai−t
考虑如何计算t=∑1≤i<k⌊aiak⌋akt=\sum_{1\leq i<k}\left \lfloor \frac{a_i}{a_k} \right \rfloor a_kt=∑1≤i<k⌊akai⌋ak
不但发现对于任意两个数u,vu,vu,v来说有下面规律⌊uv⌋v=kv,u≤kv<(k+1)v\left \lfloor \frac{u}{v} \right \rfloor v=kv,u\leq kv<(k+1)v⌊vu⌋v=kv,u≤kv<(k+1)v
枚举k,我们只需用统计出{ai,1≤i<k}\{a_i,1\leq i<k\}{ai,1≤i<k}每段区间aia_iai的个数,就可以计算ttt
Code
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
template <class T=int> T rd()
{T res=0;T fg=1;char ch=getchar();while(!isdigit(ch)) {if(ch=='-') fg=-1;ch=getchar();}while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();return res*fg;
}
const int N=300010;
template <typename T=int>
struct Fenwick
{const int n;T t[N];Fenwick(int n):n(n){memset(t,0,sizeof t);}void add(int k,T v){for(;k<=n;k+=k&-k) t[k]+=v;}T qsum(int k){T v=0;for(;k;k-=k&-k) v+=t[k];return v;}T get(int l,int r){return qsum(r)-qsum(l-1);}
};
int n;
int a[N];
int main()
{n=rd();for(int i=1;i<=n;i++) a[i]=rd();Fenwick<ll> f1(300000),f2(300000); //f1计算s f2计算tll pre=0,ans=0;for(int i=1;i<=n;i++){ans+=1ll*a[i]*(i-1);//s_1ans+=pre;//t_1ans-=f1.qsum(a[i]);// s_2for(int j=a[i];j<=300000;j+=a[i]){int l=j,r=min(300000,j+a[i]-1);ans-=f2.get(l,r)*j;//t_2f1.add(l,a[i]);}f2.add(a[i],1);pre+=a[i];printf("%lld%c",ans," \n"[i==n]);}return 0;
}