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; }