• bzoj 3643Phi的反函数


    3643: Phi的反函数

    Time Limit: 10 Sec  Memory Limit: 64 MB
    Submit: 298  Solved: 192
    [Submit][Status][Discuss]

    Description

    Input

     

    Output

     

    Sample Input

    4

    Sample Output

    5
     
      这道题我只能说是一道披着搜索外衣的数学题,核心都在数学知识上,于是数学能力令人发指的我跪了……
      在讲这道题之前我们先明确一下几点:
        1.一个数x的质因子若大于sqrt(x)则这个质因子最多只有一个。
        2.我们设pk为已知数x的第k个素因子ak为该素因子在x的素因子中有几个则φ(x)=p1^(a1-1)*(p1-1)*p2^(a2-1)*(p2-1)……
        3.由1可知我们线筛只用筛到sqrt(INF),大于它直接暴力检测。
        4.由2可知如果对于一个素数p,p-1是n的因子,则p可对答案产生贡献。
      于是知道了以上几点我们就好说多了,我们只要枚举每一个素数p,如果p-1是当前now的因子就接下去dfs并枚举a,对于那个大于sqrt(n)的因子我们直接判断如果now+1是素数且now+1>sqrt(n),我们就检查他是否对答案有贡献。
      不知道有没有人和我和Q某犇一样对于是now+1还是now还是now-1有疑问。为了周全,我还是说一下。如果当前now满足以上条件那么此时now=p^(a-1)*(p-1),由于p大于sqrt(n),a一定为1,所以就变成了now=p-1,那么p=now+1。
      差点忘说了,我们为什么会去选择dfs这种方式呢?因为貌似可以证明,在题目给的数据最多只有10个(不同的)素因子,一个素因子最多只出现30次,所以dfs没跑。
     1 #include<iostream>
     2 #include<cstdlib>
     3 #include<cstdio>
     4 #include<cstring>
     5 #include<queue>
     6 #include<algorithm>
     7 #include<cmath>
     8 #include<map>
     9 #define N 50005
    10 using namespace std;
    11 long long sq,n,ss[N],zz,ans=4294967296;
    12 bool fss[N];
    13 bool pri(long long x)
    14 {
    15     for(int i=2;i<=sqrt(x);i++)
    16         if(x%i==0)return 0;
    17     return 1;
    18 }
    19 void dfs(long long sum,long long wz,long long now)
    20 {
    21     if(sum>ans)return;
    22     if(now==1)
    23     {
    24         ans=min(ans,sum);
    25         return;
    26     }
    27     if(now>sq&&pri(now+1))ans=min(ans,(now+1)*sum);
    28     for(int i=wz;i<=zz&&ss[i]-1<=sq&&ss[i]-1<=now;i++)
    29     {
    30         if(now%(ss[i]-1)==0)
    31         {
    32             int x=now/(ss[i]-1),y=sum*ss[i];
    33             dfs(y,i+1,x);
    34             while(x%ss[i]==0)
    35             {
    36                 x/=ss[i],y*=ss[i];
    37                 dfs(y,i+1,x);
    38             }
    39         }
    40     }
    41 }
    42 int main()
    43 {
    44     scanf("%lld",&n);
    45     sq=sqrt(n);
    46     for(int i=2;i<=sqrt(n);i++)
    47     {
    48         if(!fss[i])
    49         {
    50             zz++;
    51             ss[zz]=i;
    52         }
    53         for(int j=1;j<=zz&&i*ss[j]<N;j++)
    54         {
    55             fss[i*ss[j]]=1;
    56             if(i%ss[j]==0)break;
    57         }
    58     }
    59     dfs(1,1,n);
    60     if(ans<2147483648ll) 
    61         printf("%lld
    ",ans);
    62     else printf("-1
    ");
    63     return 0;
    64 }
    View Code
  • 相关阅读:
    CCF NOI1006 捡石头
    POJ NOI MATH-7648 蓄水池水管问题
    CCF NOI1005 存款收益
    CCF NOI1004 填充矩形
    CCF NOI1003 猜数游戏
    CCF NOI1002 三角形
    Project Euler Problem 26 Reciprocal cycles
    HDU1799 循环多少次?
    CCF NOI1001 温度转换
    POJ NOI MATH-7647 余数相同问题
  • 原文地址:https://www.cnblogs.com/liutianrui/p/7536777.html
Copyright © 2020-2023  润新知