zoj 3405

第一道Catalan数的题!!!题目并不难,但关键在于时间的优化!!!

一开始的时候求阶乘相除没用唯一分解式,TLE,后乃改了,但没写成函数的形式,还是TLE,没办法

开别人的代码后,改成函数,奇迹般过了!!!

 

 

#include<iostream>
#include<stdio.h>
#include<map>
#define MAXN  123456
using namespace std;
int N,kind_factor,total_factor;
map<int,int> Q;//记录每一个数的唯一分解式;第一个数素因数,第二个数为对应指数
map<int,int> p;
int factor[MAXN],t[MAXN];
int compute_factor(int *a,map<int,int>& b,int n,int d)//很牛的方法球唯一分解式
{
    int k=0;
    for(int i=2;i*i<=n;i++)
    {
        if(n%i==0)
        {
            a[k++]=i;
            while(n%i==0)
            {
                b[i]+=d;
                n/=i;
            }
        }
    }
    if(n>1)
    {
        a[k++]=n;
        b[n]+=d;

    }

    return k;
}

long long compute_catalan(int k)
{
    long long cn_1=1,cn=1;
    for(int i=2;i<=k;i++)
    {
        cn=cn_1*2*(2*i-1)/(i+1);
        cn_1=cn;
    }
    return cn;
}

long long compute_factorial()
{
    p.clear();
    for(int i=2;i<=total_factor;i++)//计算(total_factor)!用唯一分解式表示
    {
        compute_factor(t,p,i,1);
    }
    for(int i=0;i<kind_factor;i++)//计算每一个素因子个数的阶乘用唯一分解式表示
    {
        for(int j=2;j<=Q[factor[i]];j++)
        {
            compute_factor(t,p,j,-1);
        }
    }
    map<int,int>::iterator it;
    long long res=1;
    for(it=p.begin();it!=p.end();it++)
    {
        for(int j=1;j<=(it->second);j++)
        {
            res*=(it->first);
        }
    }

    return res;
}

int main()
{

    while(scanf("%d",&N)==1)
    {
        Q.clear();
        kind_factor=compute_factor(factor,Q,N,1);
        total_factor=0;
        for(int i=0;i<kind_factor;i++)
        {
            total_factor+=Q[factor[i]];
        }

        long long kind_tree=compute_catalan(total_factor-1);

        long long temp=compute_factorial();
        unsigned long long ans=1;
        ans=temp*kind_tree;
        printf("%llu/n",ans);
    }
    return 0;

}

 

//这个代码和上面没什么不同不知为什么就是超时!!!

#include<stdio.h>
#include<iostream>
#include<math.h>
#include<map>
using namespace std;
long long N;

struct prim_factor
{
    long long fac;
    long long num;
}pf[100005];

map<int,int > Q;

int main()
{
    while(scanf("%I64d",&N)!=EOF)
    {
        //Q.clear();
        long long m=(long long)sqrt(N+0.5);
        long long  kind=0;//记录因子的种数!!!
        long long total=0;

        for(int i=2;i<=m;i++)能整除n的质数必小于等于 sqrt(x);
            if(N%i==0)
            {
              pf[kind].fac=i;
              pf[kind].num=0;
              while(N%i==0)
                    {
                        N/=i;
                        pf[kind].num++;
                        total++;
                    }
              kind++;
            }
        if(N>=2)
            {
                pf[kind].fac=N;
                pf[kind].num++;
                kind++;
                total++;
            }

            //计算树的形状数catalan
        int n=total-1;
        long long cn=1,cn_1=1;//cn为第n个Catalan数
        for(int i=2;i<=n;i++)
        {
            cn=cn_1*2*(2*(i-1)+1)/(i+1);
            cn_1=cn;
        }
//printf("%I64d/n",cn);
    //printf("%I64d/n",cn);

    //求total!的唯一分解试

        Q.clear();

        for(int i=2;i<=total;i++)
        {
            int u=i;
            int temp0=(int)sqrt(total+0.5);
            for(int j=2;j<=temp0;j++)
            {
                if(u%j==0)
                {
                    while(u%j==0)
                    {
                        Q[j]++;
                        u/=j;
                    }
                }
            }

            if(u>=2)
            {
                Q[u]++;
            }

        }

    //用(total!)/n1!/n2!/.....
        for(int i=0;i<kind;i++)
        {
            for(int j=2;j<=pf[i].num;j++)
            {
                int temp1=j;
                int temp2=(int)sqrt(temp1+0.5);
                for(int k=2;k<=temp2;k++)
                {
                    if(temp1%k==0)
                    {
                        while(temp1%k==0)
                        {
                            Q[k]--;
                            temp1/=k;
                        }
                    }
                }

                if(temp1>1)
                {
                    Q[temp1]--;
                }
            }
        }

     map<int,int >::iterator it;
     long long ans=1;
        for(it=Q.begin();it!=Q.end();it++)
        {
            for(int j=1;j<=(it->second);j++)
                ans*=(it->first);
                //printf("%I64d/n",ans);
        }

        ans*=cn;
        printf("%I64d/n",ans);

    }
    return 0;
}

 

(暴力搜索)看来是暂时过不了了!!!TLE;

#include<string.h>
#include<stdio.h>
#include<map>
#include<math.h>
#include<iostream>
#define MAXN 7000000
using namespace std;

long long int ans[MAXN];

//map<long,bool> f;
bool f(int x){
 //long y=long (sqrt(0.0+x)+1);
 for(int i=2;i*i<=x;i++) if(x%i==0) return false;
 return true;}
 
long long int dfs(int n){
 long long int sum=0;
 int i;
 if(n<MAXN){
  
  if(ans[n]) return ans[n];
  else{
  if(f(n)) return ans[n]=1;
  //long r=(long)sqrt(n+0.0);
  for( i=2;i*i<n;i++){
   if(n%i==0) sum+=dfs(i)*dfs(n/i);}
  sum*=2;
  if(i*i==n) sum+=dfs(i)*dfs(i);
  return ans[n]=sum;
   }
  }
  
 else{
  if(f(n)) return 1;
  //long r=(long)sqrt(n+0.0);long i=0;
  for(i=2;i*i<n;i++)
   if(n%i==0) sum+=dfs(i)*dfs(n/i);
  sum*=2;
  if(i*i==n) sum+=dfs(i)*dfs(i);
  return sum;}
 }

 

int main(){
 //freopen("in.txt","r",stdin);
   
    //筛素数
  /*  long i,j;
    ans[2]=1;
    for(long i=2;i<=NI;i++) f[i]=1;
    long s,e=(long)(sqrt(0.0+NI)+1);
 f[0]=f[1]=0;
 for(i=4;i<NI;i+=2) f[i]=0;
 for(i=3;i<e;i+=2) if(f[i]){
        for(s=i*2,j=i*i;j<NI;j+=s) f[j]=0;
        }*/
 

 

memset(ans,0,sizeof(ans));
int num;
 while(scanf("%d",&num)!=EOF){

 if(num<MAXN&&ans[num])  printf("%I64d/n",ans[num]);
 else{
 
  printf("%I64d/n",dfs(num));}

 }
 


 return 0;}


----------------------------------------------------------------------------------------------------------------------

这个好像是一日本人写的报告,看不懂!!!

http://d.hatena.ne.jp/iakasT/20100905/1283660510

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值