zoukankan      html  css  js  c++  java
  • HDU 5942 Just a Math Problem 容斥 莫比乌斯反演

    题意:( g(k) = 2^{f(k)} ) ,求( sum_{i = 1}^{n} g(i) ),其中( f(k))代表k的素因子个数。

    思路:题目意思很简单,但是着重于推导和简化,这是数论题的一贯思路,其中g(k)的方程可以看出是求k的无平方因子的个数,那么题目就是求1~n的无平方因字数的和了。

    首先我们可以从莫比乌斯函数入手。

    从( mu(d) )的性质有,当d为素数单次连积时( mu(d)=(-1)^k),其余d不为1时( mu(d)=0)

    那么可知( mu^{2}(d) )在d满足条件时一定为正值1,故g(k)可化为( sum_{d | i} mu^{2}(d) ) 且$$ans = sum_{i = 1}^{n}{sum_{d | i} mu^{2}(d)} $$

    接下来从容斥方向考虑。其实我们直接枚举素因子连乘的k,那么由(mu(d))函数的性质,可知当存在(k^2 | d)时,(mu(k))是不为0的,这样就去掉了素因子次数大于等于2的d,那么式子又可化成$$ {mu^{2}(d)}= { sum_{k^2|d}{mu(k)} }$$

    进一步$${sum_{k=1}^{n}sum_{k^2 | d} {mu(k)}lfloorfrac{n}{d} floor }$$ 

    (lfloorfrac{n}{d} floor)是1~n中被d整除的个数。

    其中d为k^2的整倍数。

    交换求和符号,将式子化成

    $$sum_{k = 1}^{n}{mu(k)}sum_{i=1}^{lfloor frac{n}{k^2} floor} lfloor frac{n}{k^{2} i} floor$$

    接着枚举倍数求和就可以了,其中后个求和函数在1e6范围内可以预处理。

    /** @Date    : 2016-12-04-22.09
      * @Author  : Lweleth (SoungEarlf@gmail.com)
      * @Link    : https://github.com/
      * @Version :
      */
    
    #include<bits/stdc++.h>
    #define LL long long
    #define PII pair
    #define MP(x, y) make_pair((x),(y))
    #define fi first
    #define se second
    #define PB(x) push_back((x))
    #define MMG(x) memset((x), -1,sizeof(x))
    #define MMF(x) memset((x),0,sizeof(x))
    #define MMI(x) memset((x), INF, sizeof(x))
    using namespace std;
    
    const int INF = 0x3f3f3f3f;
    const int N = 1e6+20;
    const LL mod = 1e9 + 7;
    const double eps = 1e-8;
    
    int sum1[N];
    int pri[N];
    int mu[N];
    bool vis[N];
    int c = 0;
    
    void mobius()
    {
        MMF(vis);
        mu[1] = 1;
    
        for(int i = 2; i < N; i++)
        {
            if(!vis[i])
                pri[c++] = i, mu[i] = -1;
            for(int j = 0; j < c && i * pri[j] < N; j++)
            {
                vis[i * pri[j]] = 1;
                if(i % pri[j])
                    mu[i * pri[j]] = -mu[i];
                else
                {
                    mu[i * pri[j]] = 0;
                    break;
                }
            }
        }
    }
    
    int sum(LL n)//
    {
        if(n < N && sum1[n])//小于N下且已经处理了直接返回预处理的值
            return sum1[n];
        LL t = 0;
        for(LL i = 1, j = 0; i <= n; i = j + 1)
        {
            j = n / (n / i);
            t += n / i * (j - i + 1);//优化,大于n一半的直接加
        }
        t %= mod;
        if(n >= N)
            return t;
        else
            return sum1[n] = t;
    
    }
    
    int main()
    {
        int T;
        mobius();
        while(~scanf("%d", &T))
        {
            int cnt = 0;
            while(T--)
            {
                LL n;
                LL ans = 0;
                scanf("%lld", &n);
                for(LL i = 1; i <= n / i; i++)//枚举sqrt(n)的因子
                    if(mu[i])
                        ans = (ans + sum(n/i/i) * mu[i]) % mod;//注意i取整
    
                printf("Case #%d: %lld
    ", ++cnt, (ans + mod) % mod);
            }
        }
    
        return 0;
    }
    
    
  • 相关阅读:
    LeetCode 146
    Codeforces Round #644 (Div. 3) 题解
    AtCoder Grand Contest 044
    约数个数求解+约数求和(唯一分解定理)(遍历map的写法!)
    [蓝桥杯][2013年第四届真题]危险系数(DFS)
    Codeforces Round #674 (Div. 3)(A->D(前缀和出现次数))
    Codeforces Round #673 (Div. 2)B. Two Arrays(贪心)
    Codeforces Round #672 (Div. 2)(A->C2)(B位运算,C贪心,DP)
    质数笔记
    2020 CCPC
  • 原文地址:https://www.cnblogs.com/Yumesenya/p/6132337.html
Copyright © 2011-2022 走看看