CF1553F Pairwise Modulo

分两种情况讨论

  1. \(a_i\bmod a_j\)
  • \(a_i < a_j\)

那么 \(a_j\) 对答案的贡献是 \(a_i\)

  • \(a_i > a_j\)

那么 \(a_j\) 对答案的贡献是 \(a_i-a_j \times \lfloor \dfrac{a_i}{a_j} \rfloor\),和第一个合并一下就是 \(a_i \times (i-1) - \lfloor \dfrac{a_i}{a_j} \rfloor\)

后面的这部分可以转化为枚举一个 \(l\),在区间 \([a_j \times l,a_j \times (l+1) -1]\) 上加上 \(a_j \times l\),这个可以用树状数组维护。

  1. \(a_j \bmod a_i\)
  • \(a_j<a_i\)

贡献为 \(a_j\)

  • \(a_j>a_i\)

贡献为 \(a_j-a_i \times \lfloor \dfrac{a_j}{a_i} \rfloor\),和第一种情况同理,前面一部分贡献为 \(\sum a_j\),后面同上一种情况,对于区间 \([a_i \times l,a_i \times (l+1) -1]\) 上减去上 \(a_j\) 在这个区间里的个数乘上 \(a_j \times l\),同样可以用树状数组维护。

时间复杂度为 \(O(n \log^2 n)\)

#include <bits/stdc++.h>
#define reg register
#define fi first
#define se second
#define mp std::make_pair
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
ll rd()
{
    reg ll x=0,f=0;
    reg char ch=getchar();
    while(!isdigit(ch)) (ch=='-')&&(f=1),ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return f?-x:x;
}
#define int long long
const int MAXN=2e5+10;
const int MAXM=3e5+10;
int n,a[MAXN];
int c[MAXM][2];
// 0:val 1:num
void add(reg int x,reg int v,reg int op)
{
    for(;x<MAXM;x+=(x&(-x))) c[x][op]+=v;
}
int qry(reg int x,reg int op)
{
    reg ll ret=0;
    for(;x;x-=(x&(-x))) ret+=c[x][op];
    return ret;
}
void work()
{
    n=rd();
    for(reg int i=1;i<=n;++i) a[i]=rd();
    int sum=0,ans=0;
    for(reg int i=1;i<=n;++i)
    {
        ans+=sum+1ll*a[i]*(i-1)-qry(a[i],0);
        sum+=a[i];
        for(reg int j=a[i];j<MAXM;j+=a[i])
        {
            ans-=j*(qry(std::min(j+a[i]-1,MAXM-1),1)-qry(j-1,1));
            add(j,j,0),add(std::min(j+a[i]-1,MAXM-1)+1,-j,0);
        }
        add(a[i],1,1);
        printf("%lld ",ans);
    }
    puts("");
}
#undef int
int main()
{
    int _=1;
    // _=rd();
    while(_--) work();
    return 0;
}
posted @ 2021-07-25 11:24  Nylch  阅读(43)  评论(1编辑  收藏  举报