题解:[ABC452G] 221 Substring

题目传送门

题意分析

直接推导:

\[\begin{aligned} \sum_{i=1}^n\sum_{j=1}^ma_ib_j(i\bmod j)&=\sum_{i=1}^na_i\sum_{j=1}^mb_j\left(i-j\left\lfloor\dfrac ij\right\rfloor\right)\\ &=\sum_{i=1}^nia_i\sum_{j=1}^mb_j-\sum_{i=1}^na_i\sum_{j=1}^mb_j\cdot j\left\lfloor\dfrac ij\right\rfloor\\ \end{aligned} \]

前面一部分是好算的,考虑求后面一部分。显然可以数论分块,得到 \(\mathcal O\left(n\sqrt m\right)\) 的做法。但是 \(n,m\leq10^5\),数论分块过不了。

因此考虑其他的方式处理 \(\left\lfloor\dfrac ij\right\rfloor\),可以考虑调和级数。

具体而言,枚举 \(k\),令 \(i=kj+b\)\(0\leq b<j\)。那么有 \(\left\lfloor\dfrac ij\right\rfloor=k\)

因此可以得到:

\[\begin{aligned} \sum_{i=1}^na_i\sum_{j=1}^mb_j\cdot j\left\lfloor\dfrac ij\right\rfloor&=\sum_{j=1}^mb_j\cdot j\sum_{i=1}^n\left\lfloor\dfrac ij\right\rfloor a_i\\ &=\sum_{j=1}^mb_j\cdot j\sum_{k=1}^{\left\lfloor\frac nj\right\rfloor}k\sum_{i=kj}^{kj+j-1}a_i\\ \end{aligned} \]

维护 \(a_i\) 前缀和,即可 \(\mathcal O(1)\) 计算 \(\displaystyle\sum_{i=kj}^{kj+j-1}a_i\)

因为枚举 \(k\) 的复杂度是 \(\mathcal O\left(n\log n\right)\) 的,所以总复杂度 \(\mathcal O(n\log n)\)

AC 代码

//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
typedef long long ll;
constexpr const int N=5e5,P=998244353;
int n,m,a[N+1],b[N+1],ib[N+1];
int main(){
	/*freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);*/
	
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		a[i]=(a[i]+a[i-1])%P;
	}
	for(int i=1;i<=m;i++){
		cin>>b[i];
		ib[i]=(1ll*i*b[i]+ib[i-1])%P;
		b[i]=(b[i]+b[i-1])%P;
	}
	int ans=0;
	for(int i=1;i<=n;i++){
		ans=(ans+1ll*i*(a[i]-a[i-1])%P*b[m]%P)%P;
	}
//	for(int i=1;i<=n;i++){
//		for(int l=1,r;l<=m;l=r+1){
//			int t=i/l;
//			if(!t){
//				r=m;
//			}else{
//				r=min(i/t,m);
//			}
//			ans=(ans-1ll*a[i]*t%P*(ib[r]-ib[l-1])%P)%P;
//		}
//	}
	for(int j=1;j<=m;j++){
		for(int k=1;k*j<=n;k++){
			ans=(ans-1ll*j*(b[j]-b[j-1])%P*k%P*(a[min(k*j+j-1,n)]-a[k*j-1])%P)%P;
		}
	}
	if(ans<0){
		ans+=P;
	}
	cout<<ans<<'\n';
	
	cout.flush();
	
	/*fclose(stdin);
	fclose(stdout);*/
	return 0;
}
posted @ 2026-06-29 13:45  TH911  阅读(1)  评论(0)    收藏  举报