F. Pairwise Modulo——(Harbour.Space Scholarship Contest 2021-2022 (open for everyone, rated, Div. 1 + Div. 2))

F. Pairwise Modulo

题意

给出一个长度为\(n\)的排列\(a\),定义

\[p_k = \sum_{1 \leq i,j \leq k} a_i\ mod\ a_j \]

要求输出\(p_1, \cdots, p_n\)

思路

这里暴力取模运算明显会\(T\),因此将取模运算化为:\(a_i\ mod\ a_j = a_i - \lfloor \frac{a_i} {a_j} \rfloor a_j\),并且将\(i\)\(j\)确定顺序,这样\(p\)序列就有了递推的性质,即

\[p_k = \sum_{1 \leq j \le i \le k} a_i - \lfloor \frac{a_i} {a_j} \rfloor a_j + \sum_{1 \le i \le j \le k}a_i - \lfloor \frac{a_i} {a_j} \rfloor a_j \]

\(f_k = \sum_{1 \leq j < i \le k} a_i - \lfloor \frac{a_i} {a_j} \rfloor a_j, g_k = \sum_{1 \le i < j \le k}a_i - \lfloor \frac{a_i} {a_j} \rfloor a_j\)
对于\(f_k\)\(f_k = f_{k-1} + \sum_{1 \le j < k} a_k - \lfloor \frac{a_k} {a_j} \rfloor a_j = f_{k-1} + a[k] * (k - 1) - \sum_{1\le j<k}\lfloor \frac{a_k} {a_j} \rfloor a_j\)
对于\(\sum_{1\le j<k}\lfloor \frac{a_k} {a_j} \rfloor a_j\)这一项,我们可以使用树状数组维护,
\(a_k \in [a_j,2*a_j-1]\),贡献为\(a_j\),
\(a_k \in [2*a_j, 3*a_j-1]\),贡献为\(2*a_j\)
\(\cdots\)
所以我们使用树状数组进行区间维护差分即可,对于区间\([ia_k,(i+1)a_k-1]\),在\(ia_k\)处增加\(i*a_k\),在\((i+1)*a_k\)处减去\(i*a_k\)。对于第\(k\)项直接\(query(a_k)\)求前缀和即可。

对于\(g_k = \sum_{1 \le i < j \le k}a_i - \lfloor \frac{a_i} {a_j} \rfloor a_j = f_{k-1} + \sum_{1 \le i < k}a_i - \lfloor \frac{a_i} {a_k} \rfloor a_k = f_{k-1} + \sum_{1 \le i < k}a_i - \sum_{1 \le i < k}\lfloor \frac{a_i} {a_k} \rfloor a_k\)
\(\sum_{1 \le i < k}a_i\) 直接累计计算即可,而后面的一项则需要使用树状数组维护,因为:
对于\(a_i \in [a_k,2*a_k-1]\)\(\lfloor \frac{a_i} {a_k} \rfloor\)的值为\(1\),
对于\(a_i \in [2*a_k,3*a_k-1]\)\(\lfloor \frac{a_i} {a_k} \rfloor\)的值为\(2\),
\(\cdots\)
可以对这个排列建立树状数组维护其有没有出现(\(1或者0\)),然后遍历\(a[k]\)的倍数区间查询即可得到答案,这个复杂度为\(logn\),可以接受。

Code

#include <bits/stdc++.h>
#define ll long long
#define qc ios::sync_with_stdio(false); cin.tie(0);cout.tie(0)
#define fi first
#define se second
#define PII pair<int, int>
#define PLL pair<ll, ll>
#define pb push_back
#define V vector
using namespace std;
const int N = 3e5 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9 + 7;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
int a[N];
struct Tree{
    ll c[N];
    void add(int x,ll y){
        for(;x < N; x += x&-x){
            c[x] += y;
        }
    }
    ll query(int x){
        if(x < 0)
            return 0ll;
        ll ans = 0;
        for(;x > 0;x -= x&-x)
            ans += c[x];
        return ans;
    }
    ll ask(int x,int y){
        return query(y) - query(x - 1);
    }
}A,B;
void solve(){
    int n;
    scanf("%d",&n);
    ll sum = 0,ans = 0;
    for(int i = 1; i <= n; i++){
        scanf("%d",&a[i]);
        sum += a[i];
        ans += (ll)a[i] * (i - 1);
        ans += sum - a[i];
        ans -= A.query(a[i]);
        for(int j = a[i]; j < N; j += a[i]){
            int l = j, r = min(N - 2, l + a[i] - 1);
            ans -= B.ask(l, r) * j;
            A.add(l, l);
            A.add(r + 1, -l);
        }
        B.add(a[i],1);
        printf("%lld ",ans);
    }
    printf("\n");
}

int main()
{
	#ifdef ONLINE_JUDGE
	#else
		freopen("in.txt", "r", stdin);
		freopen("out.txt", "w", stdout);
	#endif

	int T = 1;
	// scanf("%d",&T);
	while(T--){
		solve();
	}
	return 0;
}
posted @ 2021-09-26 17:38  !^^!  阅读(40)  评论(0编辑  收藏  举报