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

F. Pairwise Modulo

题意

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

pk=1i,jkai mod aj

要求输出p1,,pn

思路

这里暴力取模运算明显会T,因此将取模运算化为:ai mod aj=aiaiajaj,并且将ij确定顺序,这样p序列就有了递推的性质,即

pk=1jikaiaiajaj+1ijkaiaiajaj

fk=1j<ikaiaiajaj,gk=1i<jkaiaiajaj
对于fkfk=fk1+1j<kakakajaj=fk1+a[k](k1)1j<kakajaj
对于1j<kakajaj这一项,我们可以使用树状数组维护,
ak[aj,2aj1],贡献为aj,
ak[2aj,3aj1],贡献为2aj

所以我们使用树状数组进行区间维护差分即可,对于区间[iak,(i+1)ak1],在iak处增加iak,在(i+1)ak处减去iak。对于第k项直接query(ak)求前缀和即可。

对于gk=1i<jkaiaiajaj=fk1+1i<kaiaiakak=fk1+1i<kai1i<kaiakak
1i<kai 直接累计计算即可,而后面的一项则需要使用树状数组维护,因为:
对于ai[ak,2ak1]aiak的值为1,
对于ai[2ak,3ak1]aiak的值为2,

可以对这个排列建立树状数组维护其有没有出现(10),然后遍历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  !^^!  阅读(53)  评论(0)    收藏  举报
编辑推荐:
· 记一次.NET MAUI项目中绑定Android库实现硬件控制的开发经历
· 糊涂啊!这个需求居然没想到用时间轮来解决
· 浅谈为什么我讨厌分布式事务
· 在 .NET 中使用内存映射文件构建高性能的进程间通信队列
· 一个 java 空指针异常的解决过程
阅读排行:
· 干翻 Typora!MilkUp:完全免费的桌面端 Markdown 编辑器!
· 那些年我们一起追过的Java技术,现在真的别再追了!
· 记一次.NET MAUI项目中绑定Android库实现硬件控制的开发经历
· 从WebApi迁移到Minimal API?有了这个神器,小白也能10分钟搞定!
· 抛开官方库,手撸一个轻量级 MCP 服务端
点击右上角即可分享
微信分享提示