hdu 6434 Count (欧拉函数)
Posted tobyw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu 6434 Count (欧拉函数)相关的知识,希望对你有一定的参考价值。
Problem Description
Multiple query, for each n, you need to get $$$$$$ sum_{i=1}^{n} sum_{j=1}^{i-1}{ [gcd(i + j, i - j) = 1]} $$$$$$
Input
On the first line, there is a positive integer T, which describe the number of queries. Next there are T lines, each line give a positive integer n, as mentioned above.
T<=1e5, n<=2e7
T<=1e5, n<=2e7
Output
Your output should include T lines, for each line, output the answer for the corre- sponding n.
Sample Input
4
978
438
233
666
978
438
233
666
Sample Output
194041
38951
11065
89963
38951
11065
89963
题意
给定n,求代数式的值
分析
$$$gcd(i+j,i-j)$$$在形式上不够直观,不好分析,根据$$$gcd$$$的性质转化把它转化为$$$gcd(2j,i-j)$$$,通过交换求和顺序,并把$$$i-j$$$视为整体,原式转化为
$$$$$$ egin{align} ext{原式}&= sum_{i=1}^{n} sum_{j=1}^{i-1}{ [gcd(i + j, i - j) = 1]}&= sum_{i=1}^{n} sum_{j=1}^{i-1}{[gcd(2j, i - j) = 1]}&= sum_{j=1}^{n-1} sum_{i=j+1}^{n}{[gcd(2j, i-j) = 1]}&= sum_{j=1}^{n-1} sum_{i=1}^{j-1}{[gcd(2j, i) = 1]} end{align} $$$$$$
注意到$$$sum_{j=1}^{n-1} sum_{i=1}^{j-1}$$$其实是在二维平面上三角形的区域内求和,于是进一步改写为:
$$$$$$ sum_{i,j}^{i+jle n}{[gcd(2j, i) = 1]} $$$$$$
$$$$$$ egin{align} ext{令: }& f(n)=sum_{i,j}^{i+jle n}{[gcd(2j, i) = 1]}& g(n)=f(n)-f(n-1)=sum_{i,j}^{i+j=n}{[gcd(2j, i) = 1]} end{align} $$$$$$ 注意到当$$$i+j=n$$$时,代入$$$j=n-i$$$,可以消掉$$$j$$$,并利用gcd的性质,可以进一步简化$$$g(n)$$$:
$$$$$$ egin{align} g(n)&=sum_{i=1}^{n-1}{[gcd(2n-2i, i) = 1]}&=sum_{i=1}^{n-1}{[gcd(2n, i) = 1]} end{align} $$$$$$
所以接下来的问题就是,求$$$[1, n-1]$$$内,与$$$2n$$$互质的数有多少个。
这个问题可以继续简化,假设在$$$[1,n-1]$$$范围内,有$$$a_1,a_2,a_3,...a_p$$$与$$$2n$$$互质,那么根据gcd的性质,在$$$[n, 2n-1]$$$的范围内,相应的有$$$2n-a_1,2n-a_2,2n-a_3,...,2n-a_p$$$与$$$2n$$$互质。也就是说,两个范围内与$$$2n$$$互质的数是一样多的,所以结果很简单$$$g(n)$$$就是$$$varphi(2n)/2$$$的一半,$$$g(n)=varphi(2n)/2$$$。
$$$g(n)$$$已经不能再化简了,接下来再来看$$$f(n)$$$就容易多了,根据$$$f(n)$$$的递推式$$$g(n)=f(n)-f(n-1)$$$,很容易发现 $$$$$$ egin{align} f(n) &=sum_{i=1}^{n}g(n) & =sum_{i=1}^{n}{varphi(2n)/2}& =frac{sum_{i=1}^{n}{varphi(2n)}}{2} end{align} $$$$$$ 所以只需要对欧拉函数进行打表,并求$$$varphi(2n)$$$的前缀和,就能知道任何的$$$f(n)$$$。
但是做到这还没有结束,这道题的n高达2e7,直接对2n,也就是4e7,打表将会超时。问题就出在,$$$f(n)$$$只有$$$n$$$项,但却占用了$$$2n$$$的空间。打表发现,欧拉函数满足下面的性质:
$$$$$$varphi(2n)= egin{cases} varphi(n), & ext{n是奇数}\[2ex] 2varphi(n), & ext{n是偶数} end{cases} $$$$$$ 所以可以将$$$f(n)$$$改为:
$$$$$$ f(n) =sum_{i=1}^{n}{frac{varphi(n)}{1+n&1}} $$$$$$ 至此,只需要求出$$$varphi(i)$$$的前2e7项,并求出上面的前缀和,就能在1700ms左右求出答案。需要注意的是,前缀和需要用long long保存。
$$$$$$ egin{align} ext{原式}&= sum_{i=1}^{n} sum_{j=1}^{i-1}{ [gcd(i + j, i - j) = 1]}&= sum_{i=1}^{n} sum_{j=1}^{i-1}{[gcd(2j, i - j) = 1]}&= sum_{j=1}^{n-1} sum_{i=j+1}^{n}{[gcd(2j, i-j) = 1]}&= sum_{j=1}^{n-1} sum_{i=1}^{j-1}{[gcd(2j, i) = 1]} end{align} $$$$$$
注意到$$$sum_{j=1}^{n-1} sum_{i=1}^{j-1}$$$其实是在二维平面上三角形的区域内求和,于是进一步改写为:
$$$$$$ sum_{i,j}^{i+jle n}{[gcd(2j, i) = 1]} $$$$$$
$$$$$$ egin{align} ext{令: }& f(n)=sum_{i,j}^{i+jle n}{[gcd(2j, i) = 1]}& g(n)=f(n)-f(n-1)=sum_{i,j}^{i+j=n}{[gcd(2j, i) = 1]} end{align} $$$$$$ 注意到当$$$i+j=n$$$时,代入$$$j=n-i$$$,可以消掉$$$j$$$,并利用gcd的性质,可以进一步简化$$$g(n)$$$:
$$$$$$ egin{align} g(n)&=sum_{i=1}^{n-1}{[gcd(2n-2i, i) = 1]}&=sum_{i=1}^{n-1}{[gcd(2n, i) = 1]} end{align} $$$$$$
所以接下来的问题就是,求$$$[1, n-1]$$$内,与$$$2n$$$互质的数有多少个。
这个问题可以继续简化,假设在$$$[1,n-1]$$$范围内,有$$$a_1,a_2,a_3,...a_p$$$与$$$2n$$$互质,那么根据gcd的性质,在$$$[n, 2n-1]$$$的范围内,相应的有$$$2n-a_1,2n-a_2,2n-a_3,...,2n-a_p$$$与$$$2n$$$互质。也就是说,两个范围内与$$$2n$$$互质的数是一样多的,所以结果很简单$$$g(n)$$$就是$$$varphi(2n)/2$$$的一半,$$$g(n)=varphi(2n)/2$$$。
$$$g(n)$$$已经不能再化简了,接下来再来看$$$f(n)$$$就容易多了,根据$$$f(n)$$$的递推式$$$g(n)=f(n)-f(n-1)$$$,很容易发现 $$$$$$ egin{align} f(n) &=sum_{i=1}^{n}g(n) & =sum_{i=1}^{n}{varphi(2n)/2}& =frac{sum_{i=1}^{n}{varphi(2n)}}{2} end{align} $$$$$$ 所以只需要对欧拉函数进行打表,并求$$$varphi(2n)$$$的前缀和,就能知道任何的$$$f(n)$$$。
但是做到这还没有结束,这道题的n高达2e7,直接对2n,也就是4e7,打表将会超时。问题就出在,$$$f(n)$$$只有$$$n$$$项,但却占用了$$$2n$$$的空间。打表发现,欧拉函数满足下面的性质:
$$$$$$varphi(2n)= egin{cases} varphi(n), & ext{n是奇数}\[2ex] 2varphi(n), & ext{n是偶数} end{cases} $$$$$$ 所以可以将$$$f(n)$$$改为:
$$$$$$ f(n) =sum_{i=1}^{n}{frac{varphi(n)}{1+n&1}} $$$$$$ 至此,只需要求出$$$varphi(i)$$$的前2e7项,并求出上面的前缀和,就能在1700ms左右求出答案。需要注意的是,前缀和需要用long long保存。
总结
为什么手速这么慢,一定是有什么地方想复杂了吧。
代码
#include<stdio.h> typedef long long LL; #define maxn 20000000 int p[maxn+7]; LL arr[maxn+7]; int prepare(){ int i,j; //打表欧拉函数 for(i=1; i<=maxn; i++) p[i]=i; for(i=2; i<=maxn; i+=2) p[i]/=2; for(i=3; i<=maxn; i+=2) if(p[i]==i){ for(j=i; j<=maxn; j+=i) p[j]=p[j]/i*(i-1); } /*把规模从2n缩减到n的原因 phi(2*n)= phi(n) n奇数 2*phi(n) n偶数 arr[n] =phi(2)/2+phi(4)/2+...phi(2*n)/? =phi(1)/2+phi(2)+...phi(n)/? */ arr[1]=p[1]/2; for(int i=2;i<=20000000;++i){//求前缀和 arr[i]=arr[i-1]+p[i]/((i&1)+1); } } int main(){ prepare(); int kase,n; for(scanf("%d",&kase);kase;--kase){ scanf("%d",&n); printf("%lld ",arr[n]); } }
以上是关于hdu 6434 Count (欧拉函数)的主要内容,如果未能解决你的问题,请参考以下文章