题解:[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;
}

浙公网安备 33010602011771号