【算法】【数论】【分块】

5 阅读1分钟

atcoder.jp/contests/ab…

#include <bits/stdc++.h>  
using namespace std;  
using ll=long long;  
const int M=998244353;  
void so(){  
      
}int main(){  
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);  
    int n,m;cin>>n>>m;  
    vector<ll>a(n+1),b(m+1);  
    for(int i=1;i<=n;i++){  
        cin>>a[i];  
        a[i]%=M;  
    }for(int i=1;i<=m;i++){  
        cin>>b[i];  
        b[i]%=M;  
    }  
    vector<ll>pref(n+1,0);  
    for(int i=1;i<=n;i++){  
        pref[i]=(pref[i-1]+a[i])%M;  
    }  
    ll suma=0,sumb=0;  
    for(int i=1;i<=n;i++){  
        suma=(suma+a[i]*i%M)%M;  
    }for(int i=1;i<=m;i++){  
        sumb=(sumb+b[i])%M;  
    }ll s1=suma*sumb%M;//对每个a都要乘b  
    ll s2=0;  
    //数论分块  
    for(int i=1;i<=m;i++){//枚举每个j  
        ll f=0;  
        for(int q=1;q*i<=n;q++){//q=floor(x/j)  
            int l=q*i;//满足floor(x/j)=q的x在这个区间内  
            int r=min((q+1)*i-1,n);  
            ll sumr=(pref[r]-pref[l-1]+M)%M;  
            f=(f+q*sumr%M)%M;  
        }s2=(s2+b[i]*i%M*f%M)%M;  
    }ll ans=(s1-s2+M)%M;  
    cout<<ans<<'\n';  
}

atcoder.jp/contests/ab…

#include <bits/stdc++.h>  
using namespace std;  
using ll=long long;  
int cnt[1000010];  
int main(){  
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);  
    int n;cin>>n;  
    for(int i=0;i<n;i++){  
        int t;cin>>t;  
        cnt[t]++;  
    }for(int i=0;i<=1000005;i++){  
        cnt[i+1]+=cnt[i];  
    }ll ans=0;  
    for(int c=1;c<=1000000;c++){  
        int d=cnt[c]-cnt[c-1];  
        if(d==0)continue;  
        // 枚举 k = floor( y / c ),其中 y >= c  
        // 也就是 y 在 [k*c, (k+1)*c - 1] 时,floor(y/c) = k  
        for(int k=1;k*c<=1000000;k++){  //枚举结果
            // 区间 [k*c, (k+1)*c -1] 里的数的个数  
            int r=min(1000001,(k+1)*c-1);  
            int num=cnt[r]-cnt[k*c-1]; //什么数导致这个结果 
            ans+=(ll)k*num*d;  
        }// 减去自己和自己配对的情况(题目要求 i<j,不同位置)  
        ans-=(ll)d*(d+1)/2;  
    }cout<<ans;  
}