F. Pairwise Modulo——(Harbour.Space Scholarship Contest 2021-2022 (open for everyone, rated, Div. 1 + Div. 2))
F. Pairwise Modulo
题意
给出一个长度为的排列,定义
要求输出。
思路
这里暴力取模运算明显会,因此将取模运算化为:,并且将和确定顺序,这样序列就有了递推的性质,即
另。
对于,,
对于这一项,我们可以使用树状数组维护,
当,贡献为,
当,贡献为
所以我们使用树状数组进行区间维护差分即可,对于区间,在处增加,在处减去。对于第项直接求前缀和即可。
对于,
直接累计计算即可,而后面的一项则需要使用树状数组维护,因为:
对于,的值为,
对于,的值为,
可以对这个排列建立树状数组维护其有没有出现(),然后遍历的倍数区间查询即可得到答案,这个复杂度为,可以接受。
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;
}
Code will change the world !
【推荐】鸿蒙应用开发者激励计划,开发上架应用,现金激励超亿元!
【推荐】园子的不务正业:向创业开发者推荐「楼盘」- 杭州云谷中心
【推荐】2025 HarmonyOS 鸿蒙创新赛正式启动,百万大奖等你挑战!
【推荐】电信天翼云 2025 云上钜惠,爆款云主机2核4G只要1.5折起