• LuoguP3455 [POI2007]ZAP


    LuoguP3455 [POI2007]ZAP - Queries

    本文同步发表于博主的Cmd Markdown Blog.

    题目描述

    给定(n,m,k),求以下式子的值:

    [sum_{i=1}^n sum_{j=1}^m [gcd(i,j) = k] ]

    Input & Output's examples

    Input's examples

    2
    4 5 2
    6 4 3
    

    Output's examples

    3
    2
    

    分析

    比较显然的Mobius反演题目,没学过莫反的别尝试暴力了

    我们来一起推一下式子(注意:以下的分数默认向下取整)。

    [sum_{i=1}^n sum_{j=1}^m [gcd(i,j) = k] ]

    同时除一下(k):

    [sum_{i=1}^{frac nk} sum_{j=1}^{frac mk} [gcd(i,j) = 1] ]

    由Mobius函数的定义式:

    [sum_{d | n} mu(d) = [n = 1] ]

    我们把(gcd(i,j))代入可得。

    [sum_{d|gcd(i,j)} mu(d) = [gcd(i,j) = 1] ]

    所以,原式可以简化为:

    [sum_{i=1}^{frac nk} sum_{j=1}^{frac mk} sum_{d | gcd(i,j)} mu(d) ]

    我们变换枚举顺序,首先枚举(d),将它的求和符号提前,后面内容则变为布尔表达式

    [sum_{d=1}^{min { frac nk,frac mk }} sum_{i=1}^{frac nk} sum_{j=1}^{frac mk} [d | gcd(i,j)] mu(d) ]

    因为(d | gcd(i,j)),那么我们只需要枚举(d)的倍数即可,同时除一下(d):

    [sum_{d=1}^{min { frac nk,frac mk }} sum_{i=1}^{frac {n}{kd}} sum_{j=1}^{frac {m}{kd}} [gcd(i,j) in Z] mu(d) ]

    显然(gcd(i,j) in Z)恒成立,那么直接去掉。

    [sum_{d=1}^{min { frac nk,frac mk }} sum_{i=1}^{frac {n}{kd}} sum_{j=1}^{frac {m}{kd}} mu(d) ]

    (i,j)已经消失,那么我们直接根据乘法分配率:

    [sum_{d=1}^{min { frac nk,frac mk }} lfloor frac {n}{kd} floor lfloor frac {m}{kd} floor mu(d) ]

    因为(mu(d))是不完全积性函数,我们可以(O(n))求和。

    但是本题要求多组数据,于是我们可以数论分块一下,然后预处理(mu)前缀和。

    代码

    /* Headers */
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<cctype>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<stack>
    #include<climits>
    #include<iostream>
    #include<map>
    #define FOR(i,a,b,c) for(int i=(a);i<=(b);i+=(c))
    #define ROF(i,a,b,c) for(int i=(a);i>=(b);i-=(c))
    #define FORL(i,a,b,c) for(long long i=(a);i<=(b);i+=(c))
    #define ROFL(i,a,b,c) for(long long i=(a);i>=(b);i-=(c))
    #define FORR(i,a,b,c) for(register int i=(a);i<=(b);i+=(c))
    #define ROFR(i,a,b,c) for(register int i=(a);i>=(b);i-=(c))
    #define lowbit(x) x&(-x)
    #define LeftChild(x) x<<1
    #define RightChild(x) (x<<1)+1
    #define RevEdge(x) x^1
    #define FILE_IN(x) freopen(x,"r",stdin);
    #define FILE_OUT(x) freopen(x,"w",stdout);
    #define CLOSE_IN() fclose(stdin);
    #define CLOSE_OUT() fclose(stdout);
    #define IOS(x) std::ios::sync_with_stdio(x)
    #define Dividing() printf("-----------------------------------
    ");
    namespace FastIO{
        const int BUFSIZE = 1 << 20;
        char ibuf[BUFSIZE],*is = ibuf,*its = ibuf;
        char obuf[BUFSIZE],*os = obuf,*ot = obuf + BUFSIZE;
        inline char getch(){
            if(is == its)
                its = (is = ibuf)+fread(ibuf,1,BUFSIZE,stdin);
            return (is == its)?EOF:*is++;
        }
        inline int getint(){
            int res = 0,neg = 0,ch = getch();
            while(!(isdigit(ch) || ch == '-') && ch != EOF)
                ch = getch();
            if(ch == '-'){
                neg = 1;ch = getch();
            }
            while(isdigit(ch)){
                res = (res << 3) + (res << 1)+ (ch - '0');
                ch = getch();
            }
            return neg?-res:res;
        }
        inline void flush(){
            fwrite(obuf,1,os-obuf,stdout);
            os = obuf;
        }
        inline void putch(char ch){
            *os++ = ch;
            if(os == ot)	flush();
        }
        inline void putint(int res){
            static char q[10];
            if(res==0)	putch('0');
            else if(res < 0){putch('-');res = -res;}
            int top = 0;
            while(res){
                q[top++] = res % 10 + '0';
                res /= 10;
            }
            while(top--)	putch(q[top]);
        }
        inline void space(bool x){
        	if(!x) putch('
    ');
        	else putch(' ');
        }
    }
    inline void read(int &x){
        int rt = FastIO::getint();
        x = rt;
    }
    inline void print(int x,bool enter){
        FastIO::putint(x);
        FastIO::flush();
        FastIO::space(enter);
    }
    /* definitions */
    const int MAXN = 5e4 + 10;
    int n,m,d,u[MAXN];
    int T,prime[MAXN],cnt;
    bool isprime[MAXN];
    /* functions */
    inline long long solve(){
        long long ans = 0;
        scanf("%d%d%d",&n,&m,&d);
        if(n > m) std::swap(n,m);
        n /= d, m /= d;
        for(int i=1,j;i <= n;i = j + 1){
            j = std::min(n / (n / i), m / (m / i));
            ans += (long long) (u[j] - u[i - 1]) * (n / i) * (m / i);
        }
        return ans;
    }
    inline void init(){
        u[1] = 1;
        FOR(i,2,MAXN,1){
            if(!isprime[i]) u[i] = -1, prime[++cnt] = i;
            for(int j=1;j <= cnt && (long long) i * prime[j] <= MAXN;++j){
                isprime[i * prime[j]] = true;
                if(i % prime[j] == 0) break;
                u[i * prime[j]] = -u[i];
            }
            u[i] +=  u[i-1];
        }
    }
    int main(int argc,char *argv[]){
        init();
        scanf("%d",&T);
        while(T--) printf("%lld
    ",solve());
        return 0;
    }
    

    THE END

    LuoguP3455 [POI2007]ZAP - Queries

  • 相关阅读:
    10.2 查找同一组或分区中行之间的差
    8.7 确定当前记录和下一条记录之间相差的天数
    8.6 计算一年中周内各日期的次数
    8.5 确定两个日期之间的秒、分、小时数
    8.4 确定两个日期之间的月份数或年数
    8.2 计算两个日期之间的天数
    8.3 确定两个日期之间的工作日数目
    8.1 加减日、月、年
    7.13 计算不包含最大值和最小值的均值
    第3章 Python的数据类型 第3.1节 功能强大的 Python序列概述
  • 原文地址:https://www.cnblogs.com/herself32-lyoi/p/11168324.html
Copyright © 2020-2023  润新知