CF1553F Pairwise Modulo 题解
题意:
给定一个由不同数组成的序列 a,定义 pk 为:
pk=k∑i=1k∑j=1aimodaj其中 aimodaj 表示 ai 除以 aj 的余数。对于每个 i∈[1,n],求出 pi。
数据范围:
2≤n≤2×105, 1≤ai≤3×105 。
先来推推式子:
pk+1=k+1∑i=1k+1∑j=1aimodaj=k∑i=1k+1∑j=1aimodaj+k+1∑j=1ak+1modaj=k∑i=1k∑j=1aimodaj+k∑i=1aimodak+1+k+1∑j=1ak+1modaj=pk+k∑i=1aimodak+1+k+1∑j=1ak+1modaj方便起见,我们记 M=maxai
考虑用树状数组维护第三部分。不过在此之前,我们可以先尝试用树状数组维护第二部分。
首先总和先加上 ∑i−1j=1aj ,接着对于所有 cai≤M ,查询 [cai,(c+1)ai) 内的数的个数 c
然后总和减去 xcai 。这是因为,如果 aj 在 [cai,(c+1)ai) 内,则 ajmodai=aj−cai 。
类似地,考虑如何维护第三部分。定义数组 b ,对于所有 cai≤M 的正整数 c ,给 bcai 加上 ai
然后总和加上 iai−∑aij=1bj 。这是因为 aimodaj=ai−⌊ai/aj⌋×aj 。
因为 ai 互不相同,所以我们枚举的区间总数为 O(∑Mai)≈O(MlnM) ,参考调和级数。
因此时间复杂度 O(nlog2n)
代码:
cpp
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(3e5 + 15))
const int M = 3e5 + 5;
struct BIT
{
int tree[N];
#define lowbit(x) ((x) & (-(x)))
void add(int x,int v) {
for(int i = x; i && i <= M; i += lowbit(i)) tree[i] += v;
}
int sum(int x) {
int res = 0; for(int i = x; i; i -= lowbit(i)) res += tree[i]; return res;
}
int sum(int l,int r) { return sum(r) - sum(l - 1); }
} c1,c2;
int n,res,pre,a[N];
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
// freopen("check.in","r",stdin);
// freopen("check.out","w",stdout);
cin >> n;
for(int i = 1; i <= n; i++)
{
cin >> a[i]; res += pre; pre += a[i];
for(int j = a[i]; j <= M; j += a[i]) {
res -= j * c1.sum(j, min(j + a[i] - 1, M));
} c1.add(a[i], 1);
res += (i - 1) * a[i] - c2.sum(a[i]);
for(int j = a[i]; j <= M; j += a[i]) c2.add(j, a[i]);
cout << res << " \n"[i == n];
}
return 0;
}
参考文献:
[1] https://www.luogu.com.cn/blog/AlexWei/solution-cf1553f
[2] https://www.luogu.com.cn/blog/zankizero/solution-cf1553f