• poj2480 Longge's problem ——积性函数入门题


    题目链接:http://poj.org/problem?id=2480

    题目大意:

      给定一个数字N,求∑gcd(i, N) 1<=i <=N 的值。

    题目思路:

      x是一个数字,m与n互素,则gcd(x,m*n) = gcd(x, m) * gcd(x, n) 令g(y) = gcd(x, y) 那么g(y)是一个积性函数。令f(N) = ∑gcd(i, N) 

      满足gcd(x, n) = 1 的个数是欧拉函数φ(n),那么可以知道,满足gcd(x, n) = p 的个数可以这么求:x 和 n 同时除以 p ,那么gcd(x/p, n/p) = 1 ,那么个数就是φ(n/p)。

      分解N = p1^a1 * p2^a2 * …… *pn^an ,则f(N) = f(p1^a1 * p2^a2 * …… *pn^an) = f(p1^a1) * f(p2^a2) * …… * f(pn^an);

      可以枚举pi^ai的因数,对于f(pi^ai) = 1 * φ(pi^ai) + pi * φ(pi^(ai-1)) + pi^2 * φ(pi^(ai-2)) + …… + pi^(ai-1) * φ(pi) + pi^ai * φ(1);

      根据φ(pi^ai) = pi^ai - pi^(ai-1),那么可以化简上面的式子:f(pi^ai) = ai * pi^ai + ai * pi^(ai-1) + pi^ai = pi^ai * (ai + ai/pi + 1);

      所以,f(N) = N * (a1 + a1/p1 + 1) * (a2 + a2/p2 + 1) * …… * (an + an/pn + 1)。

      这题当然不是自己想出来的,但是学习了一下积性函数,看的神牛的解题代码:http://hi.baidu.com/lydrainbowcat/item/66a0c9088f876f12acdc70ba 说来这神牛是我的学弟,比我小一届貌似,一个高中的,竟然还都是省理的,唉……惭愧

      不说了,都是泪……什么也不想了,专注刷题。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstdlib>
     4 #include <cstring>
     5 #include <cctype>
     6 #include <stack>
     7 #include <queue>
     8 #include <map>
     9 #include <set>
    10 #include <vector>
    11 #include <cmath>
    12 #include <algorithm>
    13 #define lson l, m, rt<<1
    14 #define rson m+1, r, rt<<1|1
    15 using namespace std;
    16 typedef long long int LL;
    17 const int MAXN =  0x3f3f3f3f;
    18 const int  MIN =  -0x3f3f3f3f;
    19 const double eps = 1e-9;
    20 const int dir[8][2] = {{0,1},{1,0},{0,-1},{-1,0},{-1,1},
    21   {1,1},{1,-1},{-1,-1}};
    22 LL n, i, j, ans;
    23 int main(void){
    24 #ifndef ONLINE_JUDGE
    25   freopen("poj2480.in", "r", stdin);
    26 #endif
    27   while (~scanf("%lld", &n)){
    28     ans = n;
    29     for (i = 2; i * i <= n; ++i){
    30       j = 0;
    31       if (n % i == 0){
    32         while (n % i == 0){
    33           j++; n /= i;
    34         }
    35         ans /= i; ans = ans * (i * j - j + i);
    36       }
    37     }
    38     if (n > 1){
    39       ans /= n; ans = ans * (n - 1 + n);
    40     }
    41     printf("%lld\n", ans);
    42   }
    43 
    44   return 0;
    45 }

      开始用cin,cout超时一次,后来发现 i ,j,不应该用 int ,应该用LL,这才过了,32ms

      另外一份比较快的代码:谢谢Wahaha_hnu llw学长,还没看懂,继续有时间继续研究

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 
     5 using namespace std;
     6 
     7 typedef __int64 LL;
     8 #define N 70000
     9 
    10 LL n;
    11 LL f[N],prime[N],primeNum;
    12 LL a[N],b[N],cnt, ans;
    13 bool vis[N];
    14 void sieve()
    15 {
    16     int i,j;
    17     for(i=0;i<N;i++) f[i]=1;
    18     f[0]=f[1]=0;
    19     for(i=2;i*i<N;i++)
    20         if(f[i])
    21             for(j=i*i;j<N;j+=i)
    22                 f[j]=0;
    23     j=0;
    24     for(i=2;i<N;i++)
    25         if(f[i])
    26             prime[j++]=i;
    27     primeNum=j;
    28 }
    29 void dfs(int k,LL x)
    30 {
    31     int i,j;
    32     LL y,t;
    33     if(k==cnt)
    34     {
    35         y=n/x;
    36         for(i=0;i<cnt;i++)
    37             if(!vis[i])
    38                 y-=y/a[i];
    39         ans+=x*y;
    40 //        printf("x=%I64d y=%I64d\n",x,y);
    41         return ;
    42     }
    43     t=1;
    44     for(i=0;i<b[k];i++)
    45     {
    46         dfs(k+1, x*t);
    47         t*=a[k];
    48     }
    49     vis[k]=1;
    50     dfs(k+1, x*t);
    51     vis[k]=0;
    52 }
    53 int main()
    54 {
    55     int i,j,k;
    56 
    57     sieve();
    58     while(scanf("%I64d",&n)==1)
    59     {
    60         LL x=n;
    61         cnt=0;
    62         for(i=0;i<primeNum &&prime[i]*prime[i]<=x;i++)
    63             if(x%prime[i]==0)
    64             {
    65                 a[cnt]=prime[i], b[cnt]=0;
    66                 while(x%prime[i]==0)
    67                     b[cnt]++, x/=prime[i];
    68                 cnt++;
    69             }
    70         if(x>1) a[cnt]=x, b[cnt]=1, cnt++;
    71 //        printf("cnt=%I64d\n",cnt);
    72 //        for(i=0;i<cnt;i++)
    73 //            printf("%I64d %I64d\n",a[i], b[i]);
    74 
    75         ans=0;
    76         memset(vis,0,sizeof(vis));
    77         dfs(0,1);
    78         printf("%I64d\n",ans);
    79     }
    80   return 0;
    81 }

      这份代码可以16ms过的……

  • 相关阅读:
    OpenCL 获取Program信息
    匈牙利算法
    经常使用的webservice接口
    庞果网之高斯公式
    T4 生成实体和简单的CRUD操作
    zTree实现地市县三级级联报错(三)
    AlphaBlend
    cocos2d-x 3.0 事件处理
    rman多通道全备份脚本
    Linux下的简单好用的计算器bc
  • 原文地址:https://www.cnblogs.com/liuxueyang/p/3034750.html
Copyright © 2020-2023  润新知