六 - 搜索 - dp

题目大意:给你一个正整数 N N ,为有多少非空序列 { A n } \{A_n\} 满足:
  i [ 1 , n ] ,   A i N   i [ 1 , n ] ,    ( j = 1 i 1 [ gcd ( A i , A j ) > 1 ] ) 1 \forall\ i\in[1,n],\ A_i|N\\ \forall\ i\in[1,n],\ \ \left(\sum_{j=1}^{i-1}[\gcd(A_i,A_j)>1]\right)\le1
N 1 0 15 N\le10^{15} ,且 N N 中有不超过 6 6 个本质不同的质因子。
题解:
首先每个因数视为一个关于质因子的集合,这样一共有不超过 2 c 1 2^c-1 个集合。最朴素的dp是处理出这 2 c 1 2^c-1 种集合所有可能出现的序列,这样只能跑到c=5,跑不出c=6。
然后注意到可以继续优化,注意到每个质因子只会被最多两个集合覆盖,那么维护一个c位数,每位数0表示没有被覆盖,-1表示已经被覆盖两次了,否则表示其被哪个集合选中,然后最小表示一下这个c位数即可,实测只有三千多一点的状态。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define mod 1000000007
#define BAS 97ull
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline lint inln() { lint x;scanf("%lld",&x);return x; }
const int MXST=3263+100,MXLEN=6+10,MXTRS=63+10;queue<int> q;
int TOT,dfslst[MXST][MXLEN],id[MXLEN];unordered_map<ull,int> hvm;
int sta[MXST][MXLEN],dp[MXST],d[MXST],val[MXTRS];vector<pii> g[MXST];
inline int add_edge(int u,int v,int w) { return g[u].pb(mp(v,w)),0; }
inline ull get_hv(int *a,int c)
{
    ull res=0;
    rep(i,1,c) res=res*BAS+a[i]+10;
    return res;
}
inline int Trans(int *a,int *b,int v,int c)
{
    int mx=0,las=0;rep(i,1,c) mx=max(mx,a[i]);
    rep(i,1,c) if((v>>(i-1))&1)
    {
        if(a[i]==-1) return 0;
        if(!a[i]) b[i]=mx+1;
        else if(!las) b[i]=-1,las=a[i];
        else if(las!=a[i]) return 0;
    }
    else b[i]=a[i];
    rep(i,1,mx+1) id[i]=0;int cnt=0;
    rep(i,1,c) if(b[i]>0)
    {
        if(!id[b[i]]) id[b[i]]=++cnt;
        b[i]=id[b[i]];
    }
    return 1;
}
int Trstmp[MXLEN];
inline int getTrs(int *a,int v,int c)
{
    if(!Trans(a,Trstmp,v,c)) return 0;
    ull vl=get_hv(Trstmp,c);
    if(!hvm.count(vl)) return 0;
    return hvm[vl];
}
inline int Save(int *a,ull v,int c)
{
    hvm[v]=++TOT;
//  debug(TOT)sp<<": ";rep(i,1,c) cerr<<a[i]<<" ";cerr ln;
    rep(i,1,c) sta[TOT][i]=a[i];
    return 0;
}
int dfs(int x,int c,int all)
{
    rep(i,1,all)
    {
        if(!Trans(dfslst[x],dfslst[x+1],i,c)) continue;
        ull v=get_hv(dfslst[x+1],c);
        if(!hvm.count(v))
            Save(dfslst[x+1],v,c),dfs(x+1,c,all);
    }
    return 0;
}
inline int get_dp(int c,int all)
{
    rep(i,1,TOT)
    {
        rep(j,1,all)
        {
            int k=getTrs(sta[i],j,c);if(!k) continue;
            add_edge(i,k,val[j]),d[k]++;//,debug(i)sp,debug(j)sp,debug(k)ln;
        }
    }
    while(!q.empty()) q.pop();
    q.push(1),dp[1]=1;
    while(!q.empty())
    {
        int x=q.front();q.pop();
        Rep(i,g[x])
        {
            int y=g[x][i].fir;d[y]--;
            if(!d[y]) q.push(y);
            dp[y]=(dp[y]+(lint)g[x][i].sec*dp[x])%mod;
        }
    }
    int ans=0;
    rep(i,2,TOT) ans+=dp[i],(ans>=mod?ans-=mod:0);
    return ans;
}
int pc[MXLEN];
int main()
{
    lint n=inln();int c=0;
    for(int i=2;(lint)i*i<=n;i++) if(n%i==0)
        for(pc[++c]=1,n/=i;n%i==0;pc[c]++,n/=i);
    if(n>1) pc[++c]=1;int all=(1<<c)-1;
    rep(i,1,all)
    {
        val[i]=1;
        rep(j,0,c-1) if((i>>j)&1) val[i]*=pc[j+1];
    }
    TOT=1;
    dfs(0,c,all);
    //debug(c)sp,debug(all)sp,debug(TOT)ln;
    printf("%d\n",get_dp(c,all));
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/85138579