• 2020杭电多校第六场 7. A Very Easy Math Problem


    2020杭电多校第六场 7. A Very Easy Math Problem

    题意:

    [sum_{a_1=1}^nsum_{a_2=1}^n...sum_{a_x=1}^n(prod_{j=1}^xa_j^k)f(gcd(a_1,a_2,...,a_x))*gcd(a_1,a_2,...,a_x) ]

    其中(f(x)=0),如果(x)有平方因子;否则(f(x)=1)

    (t)组询问,数据范围为(tleq 10^4,1leq kleq 10^9,1leq xleq 10^9,1leq nleq 2 imes 10^5)

    思路:

    先做一些分析,如何求出(f)函数。

    对于一个数(x),通过算术基本定理可知一定可以写成若干个质数相乘的情况,如果某一个质数的幂次(geq 2),那么他一定是有完全平方因子的,同时它的莫比乌斯函数等于(0)

    否则它的莫比乌斯函数等于(1)(-1)

    那么(f=mu^2)

    接着来推公式吧。

    [sum_{a_1=1}^nsum_{a_2=1}^n...sum_{a_x=1}^n(prod_{j=1}^xa_j^k)f(gcd(a_1,a_2,...,a_x))*gcd(a_1,a_2,...,a_x) ]

    枚举(gcd=d),那么有

    [sum_{a_1=1}^nsum_{a_2=1}^n...sum_{a_x=1}^n(prod_{j=1}^xa_j^k)f(d)*d[gcd(a_1,a_2,...,a_x)==d] ]

    提取(d),即枚举(a_id)

    [sum_{d=1}^nsum_{a_1=1}^{frac{n}{d}}sum_{a_2=1}^{frac{n}{d}}...sum_{a_x=1}^{frac{n}{d}}(prod_{j=1}^xa_j^k)d^{kx}f(d)*d[gcd(a_1,a_2,...,a_x)==1] ]

    反演:

    [sum_{d=1}^nsum_{a_1=1}^{frac{n}{d}}sum_{a_2=1}^{frac{n}{d}}...sum_{a_x=1}^{frac{n}{d}}(a_1a_2...a_x)^kd^{kx}sum_{j|gcd}mu(j)f(d)*d ]

    提取(j),跟上面提取(d)一样的原理:

    [sum_{d=1}^nsum_{j=1}^{frac{n}{d}}mu(j)sum_{a_1=1}^{frac{n}{dj}}sum_{a_2=1}^{frac{n}{dj}}...sum_{a_x=1}^{frac{n}{dj}}(a_1a_2...a_x)^k(dj)^{kx}f(d)*d ]

    整理一下:

    [sum_{d=1}^nsum_{j=1}^{frac{n}{d}}mu(j)(dj)^{kx}f(d)d(1^k+2^k+...+(frac{n}{dj})^k)^x ]

    这一步将乘积展开了,可能有点迷惑,所以做一些解释。

    如果只有一个求和(sum_{i=1}^ni),那么就是((1+2+3+...+n))

    如果再加一个求和变成(sum_{i1=1}^nsum_{i2=1}^ni1 imes i2=sum_{i1=1}^ni1sum_{i2=1}^ni2)

    那么是不是就可以写成((1+2+3+...+n)^2)了。

    这时候如果只有一组询问就可以写了,但是多组,继续化简。

    (dj=T)

    [sum_{T=1}^nsum_{j|T}mu(j)(T)^{kx}f(frac{T}{j})frac{T}{j}(1^k+...+(frac{n}{T}^k))^x ]

    [g(T)=sum_{j|T}mu(j)(T)^{kx}f(frac{T}{j})frac{T}{j} ]

    很明显可以用倍数法预处理。

    这样在每次询问的时候就可以对(n)分块处理,时间复杂度(O(Tsqrt{n}+nlogn))

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    template<typename T>inline void read(T &x){
    	x=0; static int p;p=1;
    	static char c;c=getchar();
    	while(!isdigit(c)){if(c=='-')p=-1;c=getchar();}
    	while(isdigit(c)) {x=(x<<1)+(x<<3)+(c-48);c=getchar();}
    	x*=p;
    }
    
    const int maxn = 2e5+10;
    const int mod = 1e9+7;
    bool vis[maxn];
    int primes[maxn], cnt;
    int mu[maxn];
    int f[maxn];
    ll k, x;
    ll sum[maxn];
    
    ll dj[maxn];
    ll ndj[maxn];
    
    inline ll qmi(ll a, ll b)
    {
        ll res = 1;
        while(b)
        {
            if(b&1) res = (res*a)%mod;
            a = (a*a)%mod;
            b >>= 1;
        }
        return res%mod;
    }
    
    inline void init(int n)
    {
        mu[1] = 1;
        for(register int i = 2; i <= n; i++)
        {
            if(!vis[i])
            {
                primes[++cnt] = i;
                mu[i] = -1;
            }
            for(register int j = 1; primes[j] <= n/i; j++)
            {
                vis[primes[j]*i] = 1;
                if(i%primes[j] == 0) break;
                else mu[i*primes[j]] = -mu[i];
            }
        }
        for(register int i = 1; i <= n; i++)
            f[i] = mu[i]*mu[i];
    }
    
    int n;
    inline void solve()
    {
        read(n);
    
        ll ans = 0;
        for(int l = 1, r; l <= n; l = r+1)
        {
            r = n/(n/l);
            ans += ((sum[r]-sum[l-1])%mod+mod)%mod*ndj[n/l]%mod;
            ans = (ans%mod+mod)%mod;
        }
    
        printf("%lld
    ", ans);
    }
    
    int main()
    {
        init(200000+3);
        int _;read(_);
        read(k); read(x);
        for(int i = 1; i <= 2e5; i++)
        {
            dj[i] = qmi(i, (k*x)%(mod-1));
            ndj[i] = qmi(i, k);
        }
        for(int i = 1; i <= 2e5; i++)
        {
            ndj[i] = ndj[i]+ndj[i-1];
            ndj[i] = (ndj[i]%mod+mod)%mod;
        }
        for(int i = 1; i <= 2e5; i++)
            ndj[i] = qmi(ndj[i], x)%mod;
    
        for(int i = 1; i <= 200000; i++)
            for(int j = 1; j <= 200000/i; j++)
            {
                int T = i*j;
                sum[T] += mu[j]*dj[T]%mod*f[i]%mod*i%mod;
                sum[T] = (sum[T]%mod+mod)%mod;
            }
            
        for(int i = 1; i <= 200000; i++)
        {
            sum[i] += sum[i-1];
            sum[i] = (sum[i]%mod+mod)%mod;
        }
    
        while(_--)solve();
        return 0;
    }
    
  • 相关阅读:
    结队完成-连续最大子数组和
    一、数据库的基础简介
    十六、Shell之expect自动化交互程
    十五、Shell之数组
    十四、循环控制
    十三、Shell之select语句
    Linux系统产生随机数的6种方法
    十二、Shell之for循环
    十一、Shell之while&&until循环
    Shell补充之后台执行脚本程序
  • 原文地址:https://www.cnblogs.com/zxytxdy/p/13447457.html
Copyright © 2020-2023  润新知