bzoj 3643Phi的反函数
3643: Phi的反函数
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 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 }