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$(保证$sum\gt 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\%$:$m\le 1000$
$40\%$:$sum$为合数
$100\%$:$m\le 10^4,a_i\le 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 \neq 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 1\pmod{x}$。
假设已经找出一个最小的$r$满足:$2^r \equiv 1\pmod{x}$,则必然满足$r|x$。
设$P$为$x$的一个质因子,则必然有$2^r \equiv 1\pmod{P}$。且$2^{P-1} \equiv 1\pmod{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 1\pmod{Sum}$。
找出一个最小的$r$满足:$2^r \equiv 1\pmod{Sum}$,则必然满足$r|x$。即任何一个满足条件的$x$都是$r$的倍数。
因为$2^r\equiv1\pmod{Sum}$,所以$2^{kr}=(2^r)^k\equiv1^k=1\pmod{Sum}$。($k\in 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\n", 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"); } }