2018.09.08【校内模拟】T2 整数划分 Division (唯一分解)(状压DP)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/82531452

这里写图片描述
这里写图片描述


解析:

是的又是第二题最难。。。
是的又是一道状压 D P 。。。

而且这道题还卡空间(128MB)。。。

于是这道题就被我拿来练卡空间了。。。

然后时间就成了全 O J 最慢,空间成了全 O J 最小,不到第二小内存的一半。。。

说正事

考虑怎么凑成一个数 n 。。。

由于题目要求分出来的全部互质,也就是说 n 的同一质因子必须全部来自同一个数,设 n = i p i k i ,则若一个数的 p i 的次数必须要么为0要么为 k i ,不符合条件的全部舍弃。

由于 1 e 18 以内的数最多只有14个不同的质因子(2~41连乘),所以可以状压 D P ,要看出来还是挺不容易的。。。

对于 1 e 18 的数,我们不一定要分解它的质因数,我们通过哪些数能够凑成它来考虑怎么分解。

剩下的就是实现细节,看代码吧。


代码(空间只有2168 K B ):

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define pc putchar
#define gc getchar
#define cs const

inline
ll getint(){
    re ll num=0;
    re char c;
    while(!isdigit(c=gc()));
    while(isdigit(c))num=(num<<1)+(num<<3)+(c^48),c=gc();
    return num;
}

inline
void outint(ll a){
    static char ch[23];
    if(a==0)pc('0');
    while(a)ch[++ch[0]]=(a-a/10*10)^48,a/=10;
    while(ch[0])pc(ch[ch[0]--]);
}

inline
ll gcd(ll a,ll b){
    re ll tmp=0;
    while(b){
        tmp=a-a/b*b;
        a=b;
        b=tmp;
    }
    return a;
}

bool mark[31624];//31623<sqrt(1e9)<31624
int prime[3411],pcnt;//其中只有3410个质数
inline
void linear_sieves(int len=31623){
    for(int re i=2;i<=len;++i){
        if(!mark[i])prime[++pcnt]=i;
        for(int re j=1;i*prime[j]<=len;++j){
            mark[i*prime[j]]=true;
            if(i%prime[j]==0)break;
        }
    }
}

ll n;
int m;
bool flag1;

inline
bool check(ll x){
    if(n==n/x*x&&gcd(x,n/x)==1)return true;
    return false;
}

ll f[1<<15];

set<ll> num;
inline
void sieves(ll x){
    for(int re i=1;i<=pcnt;++i){
        if(x==x/prime[i]*prime[i])num.insert(prime[i]);
        while(x==x/prime[i]*prime[i])x/=prime[i];
    }
    if(x>1)num.insert(x);
}

inline
bool check0(){
    ll tt=n;
    for(set<ll>::iterator it=num.begin();it!=num.end();++it){
        while(tt==tt/(*it)*(*it))tt/=(*it);
    }
    if(tt>1)return false;
    return true;
}

inline
ll trans(int x){
    int cnt=0,res=0;
    for(set<ll>::iterator it=num.begin();it!=num.end();++it){
        if(x==x/(*it)*(*it))res|=(1<<cnt);
        ++cnt;
    }
    return res;
}

int a[501];
int main(){
    linear_sieves();
    n=getint();
    m=getint();
    for(int re i=1;i<=m;++i){
        ll x=getint();
        if(x==1){
            --i;
            --m;
            flag1=true;
            continue;
        }
        if(check(x)){
            sieves(x);
            a[i]=x;
        }
        else --i,--m;
    }
    if(!check0()){
        pc('0');
        return 0;
    }
    for(int re i=1;i<=m;++i){
        a[i]=trans(a[i]);
    }
    f[0]=1;
    int up=num.size();
    for(int re i=0;i<(1<<up);++i){
        if(f[i]!=0)
        for(int re j=1;j<=m;++j){
            if(a[j]>i&&(i&a[j])==0)
            f[i|a[j]]+=f[i];
        }
    }
    outint(f[(1<<up)-1]*(flag1?2:1));
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/82531452