Harbour.Space Scholarship Contest 2021-2022 ( Div. 1 + Div. 2) F. Pairwise(树状数组)
题意:
给出一个数组 a a a ,定义 f ( k ) = ∑ i , j ≤ k a i % a j f(k)=\sum\limits_{i,j \leq k} a_i\% a_j f(k)=i,j≤k∑ai%aj。 对于 k k k从1到 n n n ,输出 f ( k ) f(k) f(k)
题解:
首先, k k k变到 k + 1 k+1 k+1的过程中,增加了数 a k + 1 a_{k+1} ak+1 ,那么只需在 f ( k ) f(k) f(k)的基础上,再去计算 a k + 1 a_{k+1} ak+1的贡献即可。
那么怎么计算这个数的贡献呢?分两种情况计算。
1. 1. 1. 当 a k + 1 a_{k+1} ak+1 放后面时,我们利用树状数组找出比 a k + 1 a_{k+1} ak+1 小的数,那么这些数对 a k + 1 a_{k+1} ak+1取模还是自己本身,所以求这些数的总和即可。对于比 a k + 1 a_{k+1} ak+1 大的数,我们可以枚举区间 [ t a k + 1 , ( t + 1 ) a k + 1 − 1 ] [ta_{k+1},(t+1)a_{k+1}-1] [tak+1,(t+1)ak+1−1] ,计算出这个区间里面有多少个数,记为 c n t cnt cnt,同时也计算出这个区间内的数的总和 s u m sum sum ,那么这个区间里面的数对 a k + 1 a_{k+1} ak+1 取模的答案就是 s u m − c n t ⋅ t a k + 1 sum-cnt \cdot ta_{k+1} sum−cnt⋅tak+1
2. 2. 2. 当 a k + 1 a_{k+1} ak+1放前面时,也可以利用树状数组求出大于 a k + 1 a_{k+1} ak+1 的数的个数,记为 c n t cnt cnt,那么 a k + 1 a_{k+1} ak+1 对这些数取模还是 a k + 1 a_{k+1} ak+1 ,答案就是 c n t ⋅ a k + 1 cnt \cdot a_{k+1} cnt⋅ak+1 。对于比 a k + 1 a_{k+1} ak+1 小的数,记为 x x x ,我们可以先对这些数预先做以下操作: t r e e [ t ⋅ x ] + = x tree[t \cdot x]+=x tree[t⋅x]+=x 。
然后再查询出前缀 s u m ( t r e e [ a k + 1 ] ) sum(tree[a_{k+1}]) sum(tree[ak+1]) ,假设比 a k + 1 a_{k+1} ak+1小的数有 y y y个 那么答案就是 y ⋅ a k + 1 − s u m ( t r e e [ a k + 1 ] ) y \cdot a_{k+1} -sum(tree[a_{k+1}]) y⋅ak+1−sum(tree[ak+1]) 。
例如 :对于 1 2 5 ,1现在1 2 3 4 5所有位置加上了1 ,2在2 4 位置加上了2 ,那么5%1+5%2就可以变成 5-(1+1+1+1+1)+5-(2+2) 。其实就是预先求出 x / y ⋅ y x/y \cdot y x/y⋅y ,那么模数只要相减即可。
代码:
#pragma GCC diagnostic error "-std=c++11"
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#include<ctime>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int MAXN=3e5+5;
const int inf=0x3f3f3f3f;
ll tree[MAXN][3];
int a[MAXN];
int n=300000;
int lowbit(int i)
{
return i&-i;
}
ll sum(int i,int id)
{
ll s=0;
while(i>0)
{
s+=tree[i][id];
i-=lowbit(i);
}
return s;
}
void add(int i,int val,int id)
{
while(i<=n)
{
tree[i][id]+=val;
i+=lowbit(i);
}
}
int main()
{
int m;
cin>>m;
ll ans=0;
for(int i=1;i<=m;i++)
{
cin>>a[i];
ans+=sum(a[i]-1,1);
ans+=1ll*(sum(n,0)-sum(a[i],0))*a[i];
for(int j=2*a[i];j<=n;j+=a[i])
{
ans+=(sum(j-1,1)-sum(j-a[i],1))-1ll*(sum(j-1,0)-sum(j-a[i],0))*(j-a[i]);
if(j==n) break;
if(j+a[i]>n)
{
ans+=(sum(n,1)-sum(j,1))-1ll*(sum(n,0)-sum(j,0))*(j);
break;
}
}
if(2*a[i]>n)
{
ans+=(sum(n,1)-sum(a[i],1))-1ll*(sum(n,0)-sum(a[i],0))*(a[i]);
}
ans+=1ll*sum(a[i]-1,0)*a[i]-sum(a[i],2);
for(int j=a[i];j<=n;j+=a[i])
{
add(j,a[i],2);
}
add(a[i],a[i],1);
add(a[i],1,0);
cout<<ans<<" ";
}
}

浙公网安备 33010602011771号