赛时并没有能调出来:(
这是一个 (O(nsqrt{n}log n)) 的屑做法,主要原因是我看到了 (a_i) 互不相等,但根本没想到怎么去用。
设 (maxn=maxlimits_{i=1}^{n}a_i),(len=sqrt{maxn}) 下文将用到。
考虑对每个 (a_i) 算贡献,有 (2) 种:
-
第 (1) 种是作为被模数。
如果模数比 (a_i) 大,很明显余数为 (a_i),于是我们就只需要求模数比 (a_i) 小的。
对于 (a_i),我们再分 (2) 种情况讨论:
-
第一种是模数 (x) 小于等于 (len),对于这部分,我们发现一个只有不超过 (len) 个数,所以暴力处理。
-
第二种是模数 (x) 大于 (len),对于这部分,我们发现 (leftlfloordfrac{a_i}{x} ight floor) 小于 (len),只有不超过 (len) 个数,所以我们枚举 (leftlfloordfrac{a_i}{x} ight floor),求出 (x) 的上下界,答案为 (a_i·cnt-sumlimits x),(cnt) 为满足条件的 (x) 的个数。
-
-
第 (2) 种是作为模数。
对于 (a_i),我们依旧是分两种讨论:
-
如果 (a_i) 小于等于 (len),我们发现这样的 (a_i) 值域范围只有 (len) 个。于是,每个新加入的数,对于任意的 (j(jleq len)) 求出余数,预处理出 (sum_{i,j}) 表示模 (i) 余 (j) 的数的个数;
-
如果 (a_i) 大于 (len),我们发现,它将整个值域范围分成了不超过 (len) 段,也就是说对于任意的被模数 (x),都有 (leftlfloordfrac{x}{a_i} ight floorleq len),那就枚举 (leftlfloordfrac{x}{a_i} ight floor) 求出 (x) 的上下界,答案为 (sum x-cnt·a_i),其中 (cnt) 表示满足条件的 (x) 的个数,这两部分都可以用树状数组维护。
-
代码:
#include<bits/stdc++.h>
#define LL long long
#define F(i,a,b) for(int i=(a);i<=(b);++i)
#define DF(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
const int N=3e5+10,M=610;
int n,a[N],maxn;
LL sum[M][M],ans,l[N];
struct BIT{
LL t[N];
void add(int x,LL y){for(;x<=maxn;x+=x&-x)t[x]+=y;}
LL query(int x){if(x<0)return 0ll;LL ans=0;for(;x;x-=x&-x)ans+=t[x];return ans;}
}T1,T2;
signed main(){
cin>>n;
F(i,1,n){
cin>>a[i];
maxn=max(maxn,a[i]);
}int len=sqrt(maxn);
F(i,1,n){
ans+=a[i]*(i-1-T2.query(a[i]));
F(j,1,len){
if(j>=a[i])break;
ans+=l[j]*(a[i]%j);
}
F(j,1,len){
int l=max(len+1,a[i]/(j+1)+1),r=a[i]/j;
if(r<=len)break;
ans+=(T2.query(r)-T2.query(l-1))*a[i]-(T1.query(r)-T1.query(l-1))*j;
}
if(a[i]<=len){
F(j,1,a[i]-1)
ans+=sum[a[i]][j];
}else{
for(int j=0;j<=maxn;j+=a[i])
ans+=T1.query(min(maxn,j+a[i]-1))-T1.query(j-1)-(T2.query(min(maxn,j+a[i]-1))-T2.query(j-1))*j;
}
F(j,2,len){
int k=a[i]%j;
if(!k)continue;
sum[j][k]+=k;
}
T1.add(a[i],a[i]);T2.add(a[i],1);
l[a[i]]++;
yout<<ans<<" ";
}
return 0;
}