【51nod1363】最小公倍数之和

18 篇文章 0 订阅
4 篇文章 0 订阅

Description

给出一个n,求1-n这n个数,同n的最小公倍数的和。
例如:n = 6,1,2,3,4,5,6 同6的最小公倍数分别为6,6,6,12,30,6,加在一起 = 66。
由于结果很大,输出Mod 1000000007的结果。

Solution

这道题化简到一半,差点废了,后来经高人指点才明白……

ans=i=1ningcd(i,n)=nd|ni=1n/di[gcd(i,n/d)==1]

我们发现当存在i与x互质时, x-i与x也是对称的,换言之,与x对称的数是对称存在的,两两相加和为x,除了1。
ans=n+nd|nϕ(n/d)n/d2=n+n2d|n,d>1ϕ(d)d
我们把n的每个质因子提出来,算出它对答案的贡献,然后乘起来就可以。形如(a+b)*(c+d)=ac+ad+bc+bd
n=i=1Bpiai

d|nϕ(d)d=i=1Bj=0aiϕ(pij)pij=i=1B1+j=1ai(pi1)pi2j1=i=1B1+(pi1)pi2ai+1pipi21=i=1B1+pi2ai+1pipi+1
最后只要把d=1的状态剪去即可,即减1。
T=i=1B1+pi2ai+1pipi+1

ans=n+n2(T1)

Code

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const ll maxn=1e5;
const ll mo=1e9+7,mo2=5e8+4;
ll d[maxn],bz[maxn+5];
ll n,m,i,t,j,k,l,x,y,z,ans;
ll mi(ll x,ll y){
    if (y==1) return x;
    ll t=mi(x,y/2);
    if (y%2==0) return t*t%mo;return t*t%mo*x%mo;
}
int main(){
//  freopen("data.in","r",stdin);
    scanf("%lld",&n);
    for (i=2;i<=maxn;i++){
        if (!bz[i]) d[++d[0]]=i;
        for (j=1;j<=d[0];j++){
            if (i*d[j]>maxn) break;
            bz[i*d[j]]=1;
            if (i%d[j]==0)break;
        }
    }
    for (;n;n--){
        scanf("%lld",&x);ans=1;y=x;
        for (i=1;d[i]*d[i]<=x;i++){
            if (x%d[i]) continue;
            t=0;k=1;
            while (x%d[i]==0) x/=d[i],t++;
            k+=d[i]*(mi(d[i],2*t)-1)%mo*mi(d[i]+1,mo-2)%mo;
            ans=ans*k%mo;
        }
        k=(1+(x-1)*x)%mo;
        ans=ans*k%mo;
        ans--;
        ans=(ans*y%mo*mo2%mo+y)%mo;
        printf("%lld\n",ans);
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值