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\n",ans);
62     else printf("-1\n");
63     return 0;
64 }
View Code
posted @ 2017-09-17 19:34  Hzoi_joker  阅读(198)  评论(0编辑  收藏  举报