zoukankan      html  css  js  c++  java
  • BZOJ3643-欧拉函数,搜索

    给定一个数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)=prodlimits_{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搜索,得到可行解

    a b c x
    0 1 1 15
    4 0 0 16
    2 0 1 20
    3 1 0 24
    1 1 1 30

    发现某些偶数是无解的,随着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[N];
    int p[N], 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[n];
        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
    ",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
    ");
            else printf("%lld
    ",ans[0]);
        }
        return 0;
    }
    

      

      

      

      

  • 相关阅读:
    《A First Course in Probability》-chaper4-离散型随机变量-随机变量函数的期望
    《训练指南》——7.17
    《A First Course in Probability》-chaper4-离散型随机变量-负二项分布
    《A First Course in Probability》-chaper5-连续型随机变量-正态分布
    《University Calculus》-chaper8-无穷序列和无穷级数-比值审敛法
    Scheme实现二叉查找树及基本操作(添加、删除、并、交)
    hdu5884(多叉哈夫曼树)
    uva10857(状态压缩DP)
    hdu4055
    Controlled Tournament(状态压缩DP)
  • 原文地址:https://www.cnblogs.com/shuiming/p/7726651.html
Copyright © 2011-2022 走看看