好久没见到数论分块的题目了
先将imodj变形为i−j⌊ji⌋
再将求和公式换位为∑j=1m∑i=1nAi×Bi×(i−j×⌊ji⌋)
将不变值提取出来(∑i=1ni×Ai)×(∑j=1mBj)−∑j=1m∑i=1nAi×Bj×j×⌊ji⌋
然后我们可以发现⌊ji⌋只有每当i扩大j的时候才会变,所以可以将[k×j,k×j+j−1)放在一起计算
时间复杂度即为O(n+2n+3n⋯+1),即调和级数
AC代码
Details
#include<bits/stdc++.h>
using namespace std;
#define QAQ return
#define QWQ return 0;
#define ll long long
#define pii pair< int,int >
const int N=5e5+10, mod=998244353;
ll a[N], b[N], suma[N];
int main()
{
ios::sync_with_stdio( false );
cin.tie( nullptr ), cout.tie( nullptr );
int n, m;
ll ans=0, sumb=0;
cin>>n>>m;
for( int i=1;i<=n;i++ ) cin>>a[i], suma[i]=( suma[i-1]+a[i] )%mod;
for( int i=1;i<=m;i++ ) cin>>b[i], ( sumb+=b[i] )%=mod;
for( int i=1;i<=n;i++ ) ( ans+=a[i]*i%mod*sumb )%=mod;
for( int i=1;i<=m;i++ ) for( int k=0;k<=n;k+=i )
{
int j=min( n,k+i-1 );
if( k ) ( ans-=b[i]*i%mod*( k/i )%mod*( suma[j]-suma[k-1] ) )%=mod;
else ( ans-=b[i]*i%mod*( k/i )%mod*suma[j] )%=mod;
}
cout<<( ans+mod )%mod;
QWQ
}
时间复杂度:O(nlogn),瓶颈在于数论分块带来的调和级数