1. 程式人生 > >[51nod1363][數論]最小公倍數之和

[51nod1363][數論]最小公倍數之和

Description

給出一個n,求1-n這n個數,同n的最小公倍數的和。
例如:n = 6,1,2,3,4,5,6 同6的最小公倍數分別為6,6,6,12,30,6,加在一起 = 66。
由於結果很大,輸出Mod 1000000007的結果。

Input

第1行:一個數T,表示後面用作輸入測試的數的數量。(1 <= T <= 50000)
第2 - T + 1行:T個數A[i](A[i] <= 10^9)

Output

共T行,輸出對應的最小公倍數之和

Sample Input

3
5
6
9

Sample Output

55
66
279

題解

開始只會 T l o g n n

T*logn*\sqrt n
然後…
懶人搬運大爺題解
主要是轉成質因數的貢獻這方面很妙

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include
<ctime>
#include<map> #include<bitset> #define LL long long #define mp(x,y) make_pair(x,y) #define mod 1000000007 using namespace std; inline int read() { int f=1,x=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline void write(int x) { if(x<0)putchar('-'),x=-x; if(x>9)write(x/10); putchar(x%10+'0'); } inline void pr1(int x){write(x);printf(" ");} inline void pr2(int x){write(x);puts("");} LL pow_mod(LL a,LL b) { LL ret=1; while(b) { if(b&1)ret=ret*a%mod; a=a*a%mod;b>>=1; } return ret; } bool v[100005]; int pr[100005],plen; void getpr(int MAXN) { memset(v,true,sizeof(v)); for(int i=2;i<=MAXN;i++) { if(v[i])pr[++plen]=i; for(int j=1;j<=plen&&i*pr[j]<=MAXN;j++) { v[i*pr[j]]=false; if(!(i%pr[j]))break; } } } LL calc(int p,int s) { LL ret=0; ret=(pow_mod(p,2*s+1)-p+mod)%mod; ret=ret*pow_mod(p+1,mod-2)%mod; return (ret+1)%mod; } int main() { getpr(100000); LL inv2=pow_mod(2,mod-2); int T=read();while(T--) { int n=read();int temp=n; LL ans=1; for(int i=1;i<=plen&&pr[i]*pr[i]<=n;i++) if(!(n%pr[i])) { int sum=0; while(!(n%pr[i]))n/=pr[i],sum++; ans=ans*calc(pr[i],sum)%mod; } if(n!=1)ans=ans*calc(n,1)%mod; ans=(ans-1+mod)%mod; ans=ans*inv2%mod*temp%mod; ans=(ans+temp)%mod; pr2(ans); } return 0; }