51nod 1363 最小公倍数之和

题目:最小公倍数之和

这里写图片描述

sol:

1.qls的式子(见51nod讨论区):

i = 1 n l c m ( i , n ) = n i = 1 n i g c d ( i , n ) = n g | n 1 i n = g | i [ g c d ( i , n ) == g ] i g = n g | n i = 1 n / g [ g c d ( i , n g ) == 1 ] i = n g | n i = 1 n / g i d | g c d ( i , n / g ) μ ( d ) = n g | n d | n g μ ( d ) 1 i n g = d | i i = n g | n d | n g μ ( d ) 1 2 n g ( n g d + 1 ) = n 2 g | n n g d | n g μ ( d ) ( n / g d + 1 ) = n 2 g | n n g ( ϕ ( n g ) + [ n g == 1 ] ) = n 2 ( g | n n g ϕ ( n g ) + 1 ) = n 2 ( g | n g ϕ ( g ) + 1 )

2.弱鸡的式子

i = 1 n l c m ( i , n ) = n i = 1 n i g c d ( i , n ) = n d | n 1 i n = d | i [ g c d ( i , n ) == d ] i d = n d | n i = 1 n / d [ g c d ( i , n d ) == 1 ] i

我们设

f ( n ) = i = 1 n [ g c d ( i , n ) == 1 ] i

喜闻乐见的是,这玩意是有结论的,即
f ( n ) = i = 1 n [ g c d ( i , n ) == 1 ] i = 1 2 n ϕ ( n ) + [ n == 1 ]

如何证明呢?
1) 考虑若 g c d ( n , x ) = 1 ,则有 g c d ( n , n x ) = 1 对于 0 < x < n 成立
假设 g c d ( n , n x ) = d d ! = 1
n = k 1 d n x = k 2 d
g c d ( n , x ) = g c d ( k 1 d , k 1 d k 2 d ) = g c d ( k 1 , ( k 1 k 2 ) ) d = d > 1
与假设 g c d ( n , x ) = 1 矛盾,上式得证

2)由1)我们可以观察到1~ n 中与 n 互质的数成对出现,且每对之和为n。当n为1时只有1单独出现,则 f ( n ) 得证。

继续推式子

i = 1 n l c m ( i , n ) = n i = 1 n i g c d ( i , n ) = n d | n 1 i n = d | i [ g c d ( i , n ) == d ] i d = n d | n i = 1 n / d [ g c d ( i , n d ) == 1 ] i = n d | n f ( n d ) = n d | n 1 2 n d ϕ ( n d ) + [ n d == 1 ] = n d | n 1 2 d ϕ ( d ) + [ d == 1 ] = n 2 ( d | n d ϕ ( d ) + 1 )

扫描二维码关注公众号,回复: 3416909 查看本文章

3.dfs求解

朴素的因数分解是 O ( n ) ,不能在时限内完成。
由反素数可知一个数的因子并不多,考虑质因数分解并搜索因数求解。
预处理素数之后质因数分解复杂度大概是 n ln n
然后这个题就可以 A C

code:

#include <bits/stdc++.h>

using namespace std;

const int maxn = 1e6+10;
const int mod = 1e9+7;
const int inv2 = (mod >> 1) + 1;
typedef long long ll;

int primes[maxn];
bool check[maxn];
int oula[maxn];
int tot;
ll ans;

void init(){
    tot = 0;
    oula[1] = 1;
    for(int i = 2;i<maxn;i++){
        if(!check[i]){
            primes[++tot] = i;
            oula[i] = i - 1;
        }
        for(int j = 1;j<=tot;j++){
            if(i*primes[j]>=maxn) break;
            check[i*primes[j]] = true;
            if(i % primes[j] == 0){
                oula[i*primes[j]] = oula[i] * primes[j];
                break;
            }
            else{
                oula[i*primes[j]] = oula[i] * (primes[j] - 1);
            }
        }
    }
}

int e[maxn],p[maxn],cnt;

ll sta[maxn];
int top;

ll Mul(ll a,ll b){
    ll ret = a*b;
    if(ret >= mod) ret%=mod;
    return ret;
}

void Add(ll& x,ll y){
    x+=y;
    if(x>=mod) x-=mod;
}

void dfs(ll pos,ll val,ll Euler){
    if(pos == cnt + 1){
        ll ret = Mul(val,Euler);
        Add(ans,ret);
        // cout<<val<<' '<<Euler<<' '<<ret<<' '<<ans<<endl;
        return ;
    }
    ll ret = val;
    dfs(pos+1,val,Euler);
    ret *= p[pos];
    ll eu = Euler * (p[pos] - 1);
    if(e[pos]>0) dfs(pos+1,ret,eu);
    for(int i = 2;i<=e[pos];i++){
        ret *= p[pos];
        eu *= p[pos];
        dfs(pos+1,ret,eu);
    }
}

int main(){
    init();
    int T;
    scanf("%d",&T);
    e[0] = 0;
    p[0] = 1;
    while(T--){
        ll n;
        scanf("%d",&n);
        cnt = 0;
        int tmp = n;
        for(int i = 1;i<=tot;i++){
            if((ll)primes[i] * primes[i] > tmp) break;
            if(tmp % primes[i] == 0){
                p[++cnt] = primes[i];
                e[cnt] = 0;
                while(tmp%primes[i]==0){
                    e[cnt]++;
                    tmp/=primes[i];
                }
            }
        }
        if(tmp!=1) {
            e[++cnt] = 1;
            p[cnt] = tmp;
        }
        ans = 1;
        dfs(0,1,1);
        ans = ans * n % mod * inv2 % mod;
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/oWuHen12/article/details/82120269
今日推荐