zoukankan      html  css  js  c++  java
  • 题解 P6274 [eJOI2017]六

    搬运一下自己的博客


    神仙思路。

    状压套状压,对于每一个 $N$ 的因数,我们可以求出它带有哪些 $N$ 的质因数(注意,这里不要求质因数次数,因为两个数只要含有同一个质因数就不互质了)。然后用乘法原理优化一下就可以 $O(k2^k)$ 求出含有这些质因数的数的个数。

    然后状压,三进制,$2^k-1$ 位,第 $i$ 位的值代表有多少个质因数情况为 $i$ 的。

    这样可能不好理解,举个例子:

    $N=2^2 \times 3^2 \times 5 \times 7$

    所以 $k=4$ ,然后比如像 $84=2^2 \times 3 \times 7$ 很显然是 $N$ 的因数,此时质因数情况为 $1101$

    然后记忆化搜索即可。

    但是仍然需要优化,首先把 $3$ 进制变成 $4$ 进制更加好写,但是此时需要用两个 $unsigned \ \ long \ \ long$ 存,此时用 $map$ 又多一个 $log$ (虽然没多大事貌似),考虑使用 $hash$ ,就两位,还不用担心取模耗时间( $ull$ ),然后貌似就可以了

    细节看代码:

    #include<cstdio>
    #include<cctype>
    
    #define ull unsigned long long
    
    #define maxn 101
    #define maxN 20000002
    #define mod 1000000007
    
    inline long long read(){
        long long r=0,f=0;
        char c;
        while(!isdigit(c=getchar()))f|=(c=='-');
        while(isdigit(c))r=(r<<1)+(r<<3)+(c^48),c=getchar();
        return f?-r:r;
    }
    
    int k,cs[maxn],cnt[maxn],rel[maxn][maxn];
    
    long long n,m,p[maxn],f[maxN];//f尽量开大,hash冲突概率小一些
    
    inline void add_cnt(long long x){
        int zt=0;
        for(int i=0;i<k;i++)
            zt|=(!(x%p[i])<<i);
        cnt[zt]++;
    }
    
    inline int val(ull x,ull y,int i){
        return (i<32?(x>>(i<<1)):(y>>((i-32)<<1)))&3;
    }
    
    inline void add(ull &x,ull &y,int i){
        i<32?x+=1ull<<(i<<1):y+=1ull<<((i-32)<<1);
    }
    
    long long solve(ull x,ull y){
        ull hx=x*131+y;//hash
        hx%=maxN;
        if(f[hx])return f[hx];
        long long ans=1;
        for(int i=1;i<(1<<k);i++){
            if(val(x,y,i)&2)continue;
            ull xc=x,yc=y;
            for(int j=1;j<=rel[i][0];j++)
                if(val(x,y,rel[i][j])^2)add(xc,yc,rel[i][j]);
                //注意,这里如果等于2并不代表无解,因为没有真正加一个数进来
                //所以在这一位上超过2没有问题,如果要在这一位真正加一个数会在上面判断
            (ans+=1ll*cnt[i]*solve(xc,yc)%mod)%=mod;
        }
        return f[hx]=ans;
    }
    
    int main(){
        n=m=read();
        for(long long i=2;i*i<=m;i++){//找质因数
            if(m%i)continue;
            while(!(m%i))m/=i,cs[k]++;
            p[k++]=i;
        }
        if(m>1)cs[k]=1,p[k++]=m;
        for(int i=1;i<(1<<k);i++){
            for(int j=1;j<(1<<k);j++)//看哪些数与这个数不互质
                if(i&j)rel[i][++rel[i][0]]=j;
            cnt[i]=1;
            for(int j=0;j<k;j++)//乘法原理
                if((i>>j)&1)cnt[i]*=cs[j];
        }
        printf("%lld",(solve(0,0)-1+mod)%mod);//记得减1,因为不能不放数字
        return 0;
    }
    
  • 相关阅读:
    tile38 复制配置
    The Guardian’s Migration from MongoDB to PostgreSQL on Amazon RDS
    tile38 一款开源的geo 数据库
    sqler sql 转rest api 的docker 镜像构建(续)使用源码编译
    sqler sql 转rest api javascript 试用
    sqler sql 转rest api redis 接口使用
    sqler sql 转rest api 的docker image
    sqler sql 转rest api 的工具试用
    apache geode 试用
    benthos v1 的一些新功能
  • 原文地址:https://www.cnblogs.com/wyzwyz/p/15696792.html
Copyright © 2011-2022 走看看