• zgg的课时作业


    Description

    对任意正整数$n$,$f(n)$为满足$|x^2-y^2|=n$的有序整数对$(x,y)$的个数。

    现在给出$m$个正整数$a_1,a_2,cdots,a_m$

    令$sum=f(a_1)+f(a_2)+cdots +f(a_m)-m$(保证$sumgt 1$)

    若$sum$为合数,求出在$[1,sum]$区间内所有满足以下条件的合数$x$的个数:

    $$x|(2^x-1)$$

    若$sum$为质数,求出在$[1,sum^2]$区间内所有满足以下条件的整数x的个数:

    $$sum|(2^x-1)$$

    Input Format

    第一行给出了正整数$m$

    接下来$m$行为$m$个正整数$a_1,a_2,cdots ,a_m$

    Output Format

    第一行输出$sum$。

    第二行输出满足条件的$x$的个数。

    Sample Input

    1
    4

    Sample Output

    3
    4

    Hint

    $(x,y)=(2,0),(-2,0),(0,2),(0,-2)$

    故$sum=4-1=3$

    $3$为质数

    满足条件的$x$分别为:$2,4,6,8$,共$4$个

    【数据规模与约定】

    $40\%$:$mle 1000$

    $40\%$:$sum$为合数

    $100\%$:$mle 10^4,a_ile 10^{10}$

    解题报告

    $f(x)$的值

    根据题意,$f(n)$为满足$|x^2-y^2|=n$的有序数对$(x,y)$的个数。

    将式子稍微转变一下,变成$|(x+y)(x-y)|=n$,所以设$a=|x+y|$,$b=|x-y|$。所以我们用$[a,b]$来代替$(x,y)$,则$[a,b]$需要满足$a cdot b = n$,且$a$、$b$的奇偶性相同。

    当$x、y eq 0$时,由$(x,y)$衍生出的$(x,y)$、$(x,-y)$、$(-x,y)$、$(-x,-y)$、$(y,x)$、$(y,-x)$、$(-y,x)$、$(-y,-x)$,都是满足题意的,将它们写成$[a,b]$形式,只能写出两个,即$[a,b]$、$[b,a]$。

    当$x=0$或$y=0$时,在$(x,0)$与$(0,y)$中,必然有$x=y$,所以由$(x,y)$可以衍生出$(0,x)$、$(x,0)$、$(0,-x)$、$(-x,0)$,而写成$[a,b]$的形式只能写出一个。

    综上所述,存在满足条件的$(x,y)$序对的个数为$[a,b]$序对个数的$4$倍。

    对$n$的取值进行分类讨论,当$n$为奇数时,$n$只能被拆分乘两个奇数的乘积。设$n = prod_{i=1}^k P_i^{t_i}$($P_i$为互不相等的奇质数),则通过乘法原理易得将$n$拆分成两个奇数的乘积的方案数为$prod_{i=1}^k (t_i+1)$。

    当$n$为偶数时,$n$只能被拆分成两个偶数的乘积。设$n = 2^a cdot prod_{i=1}^k P_i^{t_i}$,则得到将$n$拆分成两个偶数的乘积的方案数为$(a - 1) cdot prod_{i=1}^k (t_i+1)$。

    最后将结果乘以$4$即可。

    $Sum$为合数

    当$Sum$为合数时,要求求出区间$[1,Sum]$内满足$x|(2^x-1)$的合数$x$的个数。

    若$x$为偶数,由于$2^x-1$必为奇数,则不存在$x$满足$x|(2^x-1)$。

    若$x$为奇数,则假设$x|(2^x-1)$。这个式子等价于:$2^x equiv 1pmod{x}$。

    假设已经找出一个最小的$r$满足:$2^r equiv 1pmod{x}$,则必然满足$r|x$。

    设$P$为$x$的一个质因子,则必然有$2^r equiv 1pmod{P}$。且$2^{P-1} equiv 1pmod{P}$,由此可得$r|(P-1)$。

    当$P$为$x$的最小质因子时(由于$x$为奇数,所以$P gt 2$),若存在$r$满足$r|(P-1)$,则$P$不为$x$的最小质因子,矛盾。所以不存在奇合数$x$满足$x|(2^x-1)$。

    综上所述,当Sum为合数是,区间$[1,Sum]$内满足$x|(2^x-1)$的合数$x$的个数为0。

    $Sum$为质数

    当$Sum$为质数时,要求求出区间$[1,sum^2]$内满足$Sum|(2^x-1)$的整数$x$的个数。

    同样的,这个式子等价于:$2^x equiv 1pmod{Sum}$。

    找出一个最小的$r$满足:$2^r equiv 1pmod{Sum}$,则必然满足$r|x$。即任何一个满足条件的$x$都是$r$的倍数。

    因为$2^requiv1pmod{Sum}$,所以$2^{kr}=(2^r)^kequiv1^k=1pmod{Sum}$。($kin Z$)。即所以任何一个$r$的倍数都满足条件。

    综上所述,在区间$[1,Sum^2]$内满足条件的$x$的个数即在该区间内$r$的倍数的个数。

    代码:

    #include <cstdio>
    
    int m, f[100010], p[10000], pn;
    long long a, sum;
    
    long long F(long long x)
    {
        long long ret = 1, t = 0;
        if (x % 4 == 2) return 0;
        if (x % 4 == 0) x /= 4;
        for (int i = 0, j, k; i < pn && x > 1; i++)
        {
            j = p[i];
            k = 1;
            while (x % j == 0)
            {
                k++;
                x /= j;
            }
            ret *= k;
        }
        if (x != 1) ret *= 2;
        return ret;
    }
    
    bool isPrime(long long x)
    {
        if (x < 100000)
        {
            return f[x] == 0;
        }
        for (int i = 0; i < pn; i++)
        {
            if (x % p[i] == 0)
            {
                return false;
            }
        }
        return true;
    }
    
    long long pow(long long x, long long p, long long mod)
    {
        if (p == 0) return 1;
        if (p == 1) return x % mod;
        if (p == 2) return x * x % mod;
        return pow(pow(x, p / 2, mod), 2, mod) * pow(x, p % 2, mod) % mod;
    }
    
    long long Find_r(long long x)
    {
        long long ret = -1;
        x--;
        for (long long i = 2; i * i <= x; i++)
        {
            if (x % i) continue;
            if (pow(2, i, x + 1) == 1) return i;
            if (pow(2, x / i, x + 1) == 1)
            {
                if (ret == -1 || x / i < ret)
                {
                    ret = x / i;
                }
            }
        }
        return ret;
    }
    
    int main()
    {
        f[0] = f[1] = 1;
        for (int i = 2; i <= 100000; i++)
        {
            if (f[i] == 0)
            {
                for (int j = i + i; j <= 100000; j += i)
                {
                    f[j] = i;
                }
                p[pn++] = i;
            }
        }
        scanf("%d", &m);
        for (int i = 0; i < m; i++)
        {
            scanf("%lld", &a);
            sum += F(a) * 4 - 1;
        }
        printf("%lld
    ", sum);
        if (isPrime(sum))
        {
            long long r = Find_r(sum);
            if (r == -1) //找不到r时即r=phi(sum)=sum-1
            {
                r = sum - 1;
            }
            sum = sum * sum / r;
            printf("%lld", sum);
        }
        else
        {
            printf("0");
        }
    }
  • 相关阅读:
    dal configure 源码分析
    dubbo源码
    mysql replace info 和 auto_increment可能产生的问题
    消息队列总结
    关于系统并发数和QPS的思考
    字符打印流及字节打印流使用
    oracle分组查询二,row_number() over()函数的使用
    oracle表函数使用table function
    Script:10g中显示Active Session Count by Wait Class
    剑指 Offer 61. 扑克牌中的顺子
  • 原文地址:https://www.cnblogs.com/lightning34/p/4598510.html
Copyright © 2020-2023  润新知