P2260 [清华集训2012]模积和

终于会用$\LaTeX$和Typora啦

$$
\sum_{i=1}^{n}\sum_{j=1}^{m}(n\%i)(m\%j)
$$

$$
\begin{align}
&\sum_{i=1}^{n}n\%i\sum_{j=1}^{m}m\%j\\
&=\sum_{i=1}^{n}(n-\lfloor n/i \rfloor *i)\sum_{j=1}^{m}(m-\lfloor m/j \rfloor *j)
\end{align}
$$

又有i$\neq$j

所以还要求
$$
\begin{align}
\sum_{i=1}^{min(n,m)}(n-\lfloor n/i \rfloor *i)(m-\lfloor m/i \rfloor *i)
\end{align}
$$
展开求,加的项可以直接等差和分块求

涉及$i^2$的项可以用平方求和公式:
$$
\sum_{i=1}^{n}i^{2}=\frac{n(n+1)(2n+1)}{6}
$$
由于本题模数不是质数,不可以用费马小定理解逆元,要先用exgcd或欧拉定理解出inv6

宁可多$\% $也不要少$\% $

 

#include<bits/stdc++.h>
using namespace std;
const int p=19940417;
const int inv6=3323403;
typedef long long ll;
int n,m;
ll ans1,ans2,ans3,ans;
ll qsum(ll n){
    return ((n*(n+1))%p*(2*n+1)%p*inv6)%p;
}
int main(){
    cin>>n>>m;
    ans1=(ll)n%p*n%p;
    ans2=(ll)m%p*m%p;
    for(int i=1;i<=n;i++){
        int t=n/i,j=n/t;
        ans1-=((ll)(i+j)*(j-i+1)/2%p)*t;    
        i=j;
        ans1%=p;
    }
    for(int i=1;i<=m;i++){
        int t=m/i,j=m/t;
        ans2-=((ll)(i+j)*(j-i+1)/2%p)*t;
        i=j;
        ans2%=p;    
    }
    ans3=((ll)min(n,m)*n%p)*m;
    for(int i=1;i<=min(n,m);i++){
        int t1=n/i;
        int t2=m/i;
        int j=min(n/t1,m/t2);
        ans3-=((ll)(i+j)*(j-i+1)/2*t1%p)*m%p;
        ans3-=((ll)(i+j)*(j-i+1)/2*t2%p)*n%p;
        ans3+=((ll)(qsum(j)-qsum(i-1))*t1%p)*t2;
        i=j;
        ans3=(ans3%p+p)%p;
    }
    ans=(ans1*ans2%p-ans3+p)%p;
    cout<<ans<<endl;
    return 0;
}

 

posted @ 2019-07-24 17:02  天才美少女雪乃  阅读(191)  评论(0编辑  收藏  举报