您的位置:首页 > 其它

BZOJ3643-欧拉函数,搜索

2017-10-25 01:50 411 查看
给定一个数x,我们可以求出phi(x)

那给定一个数k(k<1e6),如何求出phi(x)=k的解呢

容易知道k为奇数时唯有k=1有解x=1,其余无解

假设n有素幂因子分解$n={p_1}^{a_1}{p_2}^{a_2}\cdots{p_k}^{a_k}$

因为$\phi(x)=\prod\limits_{j=1}^{k}{p_j}^{a_j-1}(p_j-1)$

所以$1<p_j<=k$且$(p_j-1)\mid k$

由此筛选出一些质数,同时记录它的最高幂次

然后用dfs遍历所有的情况,找到答案就将答案加入ans

以k=8为例,设$x=2^a3^b5^c$

对于2,有$(2-1)2^{a-1}\mid 8$,则a最大为4

对于3,有$(3-1)3^{b-1}\mid 8$,则b最大为1

对于5,有$(5-1)5^{c-1}\mid 8$,则c最大为1

再进行bfs搜索,得到可行解

abcx
01115
40016
20120
31024
11130
发现某些偶数是无解的,随着x的增大,phi(x)似乎越来越稀疏

代码

#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N=500000+5;
bool prime
;
int p
, tot=0;
//线筛
void initP(){
for(int i=2;i<N;i++)prime[i]=true;
for(int i=2;i<N;i++){
if(prime[i])p[tot++]=i;
for(int j=0;j<tot&&i*p[j]<N;j++){
prime[i*p[j]]=false;
if(i%p[j]==0)break;
}
}
}
//快速幂
LL qpow(LL a,LL b){
LL ret=1;
while(b){
if(b&1)ret=(ret*a);
a=(a*a);
b>>=1;
}
return ret;
}
typedef pair<LL,LL> pr;
vector<LL> ans;
vector<pr>v;
int num[100];//保存状态
void add(){
LL ret=1;
for(int i=0;i<v.size();i++){
if(num[i])ret*=qpow(v[i].first,num[i]);
}
ans.push_back(ret);
}
//now代表当前状态的欧拉函数值
void dfs(int cur,LL now,LL n){
if(now==n&&cur==v.size())add();//找到答案
if(now>n||cur==v.size())return;//剪枝与边界
dfs(cur+1,now,n);       //cur位置上的数为0
now*=v[cur].first-1;
num[cur]=1;
dfs(cur+1,now,n);       //cur位置上的数为1
for(int i=1;i<v[cur].second;i++){
now*=v[cur].first;
num[cur]++;
dfs(cur+1,now,n);   //cur位置上的数>1
}
num[cur]=0;               //回溯
}
bool isPrime(LL n){
if(n<N)return prime
;
for(int i=0;i<tot;i++){
if(n%p[i]==0)return false;
}
return true;
}
void solve(LL n){
v.clear();
ans.clear();
memset(num,0,sizeof num);
LL m,tmp,last=n;
//分解质因数
for(int i=0;i<tot&&p[i]<n;i++){
if(n%(p[i]-1)==0){
m=1;
tmp=n/(p[i]-1);
while(tmp%p[i]==0)m++,tmp/=p[i];
//printf("%d - %d\n",p[i],m);
v.push_back(pr(p[i],m));
}
}
if(isPrime(n+1))v.push_back(pr(n+1,1));
dfs(0,1,n);
sort(ans.begin(),ans.end());   //排序
}
int main(){
initP();
LL n;
while(~scanf("%lld",&n)){
solve(n);
if(ans.size()==0||ans[0]>(1LL<<31))printf("-1\n");
else printf("%lld\n",ans[0]);
}
return 0;
}


  

  

  

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: