bestcode#6—1003 HDU 4983 Goffi and GCD 【欧拉函数】

来源:互联网 发布:天敏智能网络电视盒 编辑:程序博客网 时间:2024/06/05 15:05

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4983

题目大意:给出n和k,求出满足条件

gcd(na,n)×gcd(nb,n)=nk.

的a和b。

首先可以得到的是gcd(n,x)< n 的,所以当k大于2时是无解的,当k等于2时,a=n,b=n才能得到n^2,只有一组。

主要是n=1的情况。

最开始做这个题目的时候是这样想的。先把一个数分为质因数的形式。

/*=========================================    质因数分解    给一个正整数,将N分解质因数(N不大)    输入:n    输出:  tot 不同质因数个数            a[] 表示第i个质因数的值            b[] 表示第i个质因数的个数    复杂度:O(sqrt(N))=========================================*/#define maxn 1111int a[maxn], b[maxn], tot = 0;void factor(int n, int a[], int b[], int &tot) {    int tmp, now;    tmp = (int)(sqrt(n) + 1);    tot = 0;    now = n;    for (int i = 2; i <= tmp; i++) if (now % i == 0) {        a[tot] = i, b[tot] = 0;        while(now % i == 0) {            b[tot]++;            now /= i;        }        tot++;    }    if (now != 1) a[tot] = now, b[tot++] = 1;}

比如:800  可以分为  2^5  *  5^2 ,根据得到的质因子可以得出其约数:

180024004200810016503225516010802040
402080101605253250161008200440028001
对于每一个约数来说:比如在1~800中与800公约数为2的约数的个数是:euler(800/2=400)个,

比如这一组:5*160=800 在1~800中与800的公约数为5的个数为euler(800/5=160)个,在1~800中与800的公约数为160的个数为euler(800/160=5)个。

所以在5*160这一组中一共的个数为:erler(5)*euler(160)个。

然后遇见了问题,找出了其质因数后不知道怎么找出所有的约数,然后没有做出来,后来看题解其实发现可以直接暴力的,sqrt(n)的复杂度。时间上是可以过的。

还有一点要注意的是要特判n是否等于1。如果n等于1,则直接输出1 。

#include<stdio.h>#include<algorithm>#include<iostream>#include<vector>#include<string.h>#define LL long longusing namespace std;LL n,k;LL euler(LL x) {    LL res = x;    for (LL i = 2; i <= x / i; i++) if (x % i == 0) {        res = res / i * (i - 1);        while(x % i == 0) x /= i;    }    if (x > 1) res = res / x * (x - 1);    return res;}const LL mod=1000000007;int main(){    while(scanf("%I64d%I64d",&n,&k)!=EOF)    {       if(n==1) {printf("1\n");  continue;}       if(k>2)  {printf("0\n");  continue;}       if(k==2) {printf("1\n");  continue;}       else       {           LL ans=0;           for(LL i=1;i*i<=n;++i)           {               if(n%i==0)               {                   LL x=n/i;                   if(i*i==n) ans+=euler(x)*euler(i);                   else ans+=euler(x)*euler(i)*2;                   ans%=mod;               }           }           printf("%I64d\n",ans);       }    }    return 0;}
本来想直接打表1000000000/2的表,发现太大了打不了...... 

后来看题解发现了一个人用的map打的表,想想还是很屌的,时间复杂度缩短了一半。

map<int,int> mp;int phi(int n){  int i,mul,nn;  if (n==1) return 1;  if (mp.find(n)!=mp.end()) return mp[n];  for (i=2;i*i<=n;i++)    if (n%i==0)    {      nn=n;      nn/=i;      mul=(i-1);      while (nn%i==0)      {        nn/=i;        mul*=i;      }      mp[n]=phi(nn)*mul;      return phi(nn)*mul;    }  mp[n]=n-1;  return n-1;}

注意在main函数里面要有一个操作:

mp.clear();







gcd(na,n)×gcd(nb,n)=nk.
0 0
原创粉丝点击