Counting Factor Trees [ZOJ 3405]

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4013

记忆化搜索,学到啦用map做映射不用担心数组开多大的问题,还有map<vector<int>,int>vis;

可以对一个list进行映射,由于10^9以内的素数因子的组合很少,可以记忆化。

View Code
//记忆化搜索,学到啦用map做映射不用担心数组开多大的问题,还有map<vector<int>,int>vis;

//可以对一个list进行映射,由于10^9以内的素数因子的组合很少,可以记忆化。
const int MM = 11111;
typedef long long int64;
int N;
int prm[MM], cnt;
bool isp[MM];

int get_prime(int n) {
    int i,j,k=0;
    int s, e=(int)(sqrt(0.0+n)+1);
    for(i=0;i<=n;i++) isp[i]=true;
    prm[k++]=2; isp[0]=isp[1]=false;
    for(i=4;i<n;i+=2) isp[i]=false;
    for(i=3;i<e;i+=2) if(isp[i]) {
        prm[k++]=i;
        for(s=(i<<1), j=i*i; j<n ; j+=s) isp[j]=false;
    }
    for(; i<n ; i+=2) if(isp[i]) prm[k++]=i;
    return k; 
}

//1000000000
map<vector<int>,int64>vis;
map<int,int64>dp;

int64 dfs(int x) {
    if(x<MM && isp[x]) return 1;
    if(dp[x]) return dp[x];
    vector<int>a; int m=x,j;
    for(j=0;j<cnt && prm[j]*prm[j]<=m;j++) {
        if(m%prm[j]==0) {
            int cc=0;
            while(m%prm[j]==0) cc++,m/=prm[j];
            a.push_back(cc);
        }
    }
    if(m>1) a.push_back(1);
    sort(a.begin(),a.end());
    if(vis[a]) return vis[a];
    int64 res=0,tmp;
    int tt=(int)sqrt(x*1.0)+1;
    bool ff=false;
    for(int i=2;i<tt;i++) if(x%i==0) {
        ff=true;
        tmp=dfs(x/i)*dfs(i);
        if((i*i)!=x) tmp<<=1;
        res+=tmp;
    }
    if(!ff) res=1;
    if(!dp[x]) dp[x]=res;
    vis[a]=res;
    return res;
}
void solve() {
    int i,j,k,tt;
    int64 ans=0,tmp;
    if(dp[N]) {printf("%lld\n",dp[N]);}
    else {
        ans=dfs(N);
        printf("%lld\n",ans);
    }
}

int main() {
    cnt=get_prime(MM); vis.clear(); dp.clear();
    while(scanf("%d",&N)!=EOF) solve();
    return 0;
}

 对N进行因式分解有N=p1^r1p2^r2.......pn^rn; 记sum=r1+r2+..+rn,则sum个节点能组成h(sum)(Catlan数)个二叉树。

N=p1^r1p2^r2.......pn^rn的排列组合*h(sum)=ans。

View Code
const int MM = 55555;
const int maxn = 80;
typedef long long int64;
//typedef __int64 int64;
//#define debug puts("wrong")
int N;
int prm[MM], cnt;
int64 com[maxn][maxn];
bool isp[MM];

void get_com() {
    int i,j,k;
    for(i=0;i<maxn;i++) {
        com[i][0]=1;
        for(j=1;j<=i;j++) com[i][j]=com[i-1][j-1]+com[i-1][j];
    }
}

int get_prime(int n) {
    int i,j,k=0;
    int s, e=(int64)(sqrt(0.0+n)+1);
    for(i=0;i<=n;i++) isp[i]=true;
    prm[k++]=2; isp[0]=isp[1]=false;
    for(i=4;i<n;i+=2) isp[i]=false;
    for(i=3;i<e;i+=2) if(isp[i]) {
        prm[k++]=i;
        for(s=(i<<1), j=i*i; j<n ; j+=s) isp[j]=false;
    }
    for(; i<n ; i+=2) if(isp[i]) prm[k++]=i;
    return k; 
}

void solve() {
    int i,j,k,tmp=N,sum=0;
    int64 ans=1;
    for(i=0;i<cnt && prm[i]*prm[i]<=N;i++) {
        if(tmp%prm[i]==0) {
            int cc=0;
            while(tmp%prm[i]==0) cc++,tmp/=prm[i];
            sum+=cc;
            ans*=com[sum][cc];
        }
    }
    if(tmp>1) sum++,ans*=sum;
    sum--;
    ans*=com[sum<<1][sum]/(sum+1);
    printf("%lld\n",ans);
}

int main() {
    cnt=get_prime(MM); get_com();
    while(scanf("%d",&N)!=EOF) solve();
    return 0;
}

 

posted @ 2013-04-29 10:34  zhang1107  阅读(260)  评论(0编辑  收藏  举报