我终于做出来了!!!!!(虽然看了题解。。。)
Ps:大神的题解太牛了,我看了一个多小时才看懂。。。
昨天那道题吧,认真想了一会,我就找着了门道,其实就是sum(φ(m)),m为n的约数(1除外)且能被一个完全平方数整除。接着就是枚举,然后求欧拉函数。提交!
我本以为能骗那么个三四十分的,谁知——0分!!!!!所有的点超时!!!
我的天啊,太不人道了!10分都不给我。。。
接着我就试着打个欧拉函数表,优化一下因数分解的方法。然而,并没有什么卵用。。。
于是,我屈服了,打开了大神的题解和代码。
我本以为看了一眼后一切问题就会迎刃而解,可是理想很丰满,现实很骨感。。。
“天啊!”
“这写的都是啥!!!”
“这是什么鬼东西!!!!”
其实我的基本思路是对的,这道题无非就是求上述的那些东西。但是我们的解题方法却相差很远。打个比方吧,我走路,人家坐飞机。我在前面已经将我的步子一一说明了。而至于人家坐的是什么“飞机”呢,接下来就是见证奇迹的时刻:
1. 不直接枚举能被某个完全平方数整除的n的约数,而是枚举既是n的因子又不是任何一个大于1的完全平方数的倍数的数,而本题的答案就是n减去既是n的因子又不是任何一个大于1的完全平方数的倍数的数的欧拉函数的总和。
2. 接下来就是分解质因数,而我也恰恰是在这里卡了好久,因为题解了忽然冒出了一个Pollard rho算法,让我立马就蒙了。然后,我就在网上翻了一个小时的资料,找这个算法。。。至于这个算法是什么,我在此就不做赘述了。以下是对我有较大帮助的几篇文章:
https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm
http://www.cnblogs.com/jackiesteed/articles/2019910.html
http://blog.sina.com.cn/s/blog_86a9d97201015cj7.html
接下来请大家继续欣赏“飞机”。。。
3. 在找质因数的过程中,我们或许会用到质数判断的算法,在我的程序中,我用的是枚举法(我也是醉了。。。)。但是,人家的代码让我想起了一个奇怪的算法。这个算法我曾经用过一次,它miller rabin算法。不过我现在差不多忘光光了,所以我也借此温习了一番。至于这个算法是什么,我在此就不做赘述了。。。
以下是对我有较大帮助的一篇文章:
http://blog.chinaunix.net/uid-26856484-id-3182166.html
最后附上本题AC代码(官方标程)
#include<cstdio>
#include<algorithm>
#define C 2730
#define S 3
using namespace std;
typedef long long ll;
int T,t,i;
ll n,m,q[100];
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
inline ll mul(ll a,ll b,lln){return(a*b-(ll)(a/(long double)n*b+1e-3)*n+n)%n;}
inline ll pow(ll a, ll b, ll n)
{
lld=1;
a%=n;
while(b){
if(b&1)d=mul(d,a,n);
a=mul(a,a,n);
b>>=1;
}
return d;
}
inline bool check(ll a,ll n){
llm=n-1,x,y;int i,j=0;
while(!(m&1))m>>=1,j++;
x=pow(a,m,n);
for(i=1;i<=j;x=y,i++){
y=pow(x,2,n);
if((y==1)&&(x!=1)&&(x!=n-1))return 1;
}
return y!=1;
}
inline bool miller_rabin(int times,ll n){
if(n==1)return 0;
if(n==2)return 1;
if(!(n&1))return 0;
while(times--)if(check(rand()%(n-1)+1,n))return 0;
return 1;
}
inline ll pollard_rho(ll n,int c){
lli=1,k=2,x=rand()%n,y=x,d;
while(1){
i++,x=(mul(x,x,n)+c)%n,d=gcd(y-x,n);
if(d>1&&d<n)return d;
if(y==x)return n;
if(i==k)y=x,k<<=1;
}
}
void findfac(ll n,int c){
if(n==1)return;
if(miller_rabin(S,n)){
q[++t]=n;
return;
}
llm=n;
while(m==n)m=pollard_rho(n,c--);
findfac(m,c),findfac(n/m,c);
}
int main()
{
scanf("%d",&T);
while(T--){
scanf("%lld",&n);
t=0;
findfac(n,C);
sort(q+1,q+t+1);
for(i=m=1;i<=t;i++)if(q[i]!=q[i-1])m*=q[i];
printf("%lld\n",n-m);
}
return 0;
}
llm=n;
while(m==n)m=pollard_rho(n,c--);
findfac(m,c),findfac(n/m,c);
}
int main()
{
scanf("%d",&T);
while(T--){
scanf("%lld",&n);
t=0;
findfac(n,C);
sort(q+1,q+t+1);
for(i=m=1;i<=t;i++)if(q[i]!=q[i-1])m*=q[i];
printf("%lld\n",n-m);
}
return 0;
}