hdu 6434 Count (歐拉函數)
阿新 • • 發佈:2018-08-22
二維 n) pos itl put 要求 art efi 歐拉函數
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 Sample Output 194041
38951
11065
89963 題意 給定n,求代數式的值 分析 $$$gcd(i+j,i-j)$$$在形式上不夠直觀,不好分析,根據$$$gcd$$$的性質轉化把它轉化為$$$gcd(2j,i-j)$$$,通過交換求和順序,並把$$$i-j$$$視為整體,原式轉化為
$$$$$$
\begin{align}
\text{原式}&= \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+j\le n}{[gcd(2j, i) = 1]} $$$$$$
$$$$$$ \begin{align} \text{令: }& f(n)=\sum_{i,j}^{i+j\le 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)$$$:
$$$$$$ \begin{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)$$$,很容易發現 $$$$$$ \begin{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)= \begin{cases} \varphi(n), & \text{n是奇數}\\[2ex] 2\varphi(n), & \text{n是偶數} \end{cases} $$$$$$ 所以可以將$$$f(n)$$$改為:
$$$$$$ f(n) =\sum_{i=1}^{n}{\frac{\varphi(n)}{1+n\&1}} $$$$$$ 至此,只需要求出$$$\varphi(i)$$$的前2e7項,並求出上面的前綴和,就能在1700ms左右求出答案。需要註意的是,前綴和需要用long long保存。 總結 為什麽手速這麽慢,一定是有什麽地方想復雜了吧。 代碼
題目鏈接
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.978
438
233
666 Sample Output 194041
38951
11065
89963 題意 給定n,求代數式的值 分析 $$$gcd(i+j,i-j)$$$在形式上不夠直觀,不好分析,根據$$$gcd$$$的性質轉化把它轉化為$$$gcd(2j,i-j)$$$,通過交換求和順序,並把$$$i-j$$$視為整體,原式轉化為
$$$$$$ \sum_{i,j}^{i+j\le n}{[gcd(2j, i) = 1]} $$$$$$
$$$$$$ \begin{align} \text{令: }& f(n)=\sum_{i,j}^{i+j\le 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)$$$:
$$$$$$ \begin{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)$$$,很容易發現 $$$$$$ \begin{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)= \begin{cases} \varphi(n), & \text{n是奇數}\\[2ex] 2\varphi(n), & \text{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\n",arr[n]); } }
hdu 6434 Count (歐拉函數)