题解 CF1553F 【Pairwise Modulo】

赛时并没有能调出来:(

这是一个 \(O(n\sqrt{n}\log n)\) 的屑做法,主要原因是我看到了 \(a_i\) 互不相等,但根本没想到怎么去用。

\(maxn=\max\limits_{i=1}^{n}a_i\)\(len=\sqrt{maxn}\) 下文将用到。

考虑对每个 \(a_i\) 算贡献,有 \(2\) 种:

  • \(1\) 种是作为被模数。

    如果模数比 \(a_i\) 大,很明显余数为 \(a_i\),于是我们就只需要求模数比 \(a_i\) 小的。

    对于 \(a_i\),我们再分 \(2\) 种情况讨论:

    1. 第一种是模数 \(x\) 小于等于 \(len\),对于这部分,我们发现一个只有不超过 \(len\) 个数,所以暴力处理。

    2. 第二种是模数 \(x\) 大于 \(len\),对于这部分,我们发现 \(\left\lfloor\dfrac{a_i}{x}\right\rfloor\) 小于 \(len\),只有不超过 \(len\) 个数,所以我们枚举 \(\left\lfloor\dfrac{a_i}{x}\right\rfloor\),求出 \(x\) 的上下界,答案为 \(a_i·cnt-\sum\limits x\)\(cnt\) 为满足条件的 \(x\) 的个数。

  • \(2\) 种是作为模数。

    对于 \(a_i\),我们依旧是分两种讨论:

    1. 如果 \(a_i\)​ 小于等于 \(len\)​,我们发现这样的 \(a_i\)​ 值域范围只有 \(len\)​ 个。于是,每个新加入的数,对于任意的 \(j(j\leq len)\)​ 求出余数,预处理出 \(sum_{i,j}\)​ 表示模 \(i\)​ 余 \(j\)​ 的数的个数;

    2. 如果 \(a_i\)​ 大于 \(len\)​,我们发现,它将整个值域范围分成了不超过 \(len\)​ 段,也就是说对于任意的被模数 \(x\)​,都有 \(\left\lfloor\dfrac{x}{a_i}\right\rfloor\leq len\)​,那就枚举 \(\left\lfloor\dfrac{x}{a_i}\right\rfloor\)​ 求出 \(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;
}
posted @ 2021-07-24 14:57  zhaohaikun  阅读(118)  评论(0编辑  收藏  举报