zoukankan      html  css  js  c++  java
  • Choose and divide(唯一分解定理)

    首先说一下什么是唯一分解定理

    唯一分解定理:任何一个大于1的自然数N,如果N不是质数,那么N可以分解成有限个素数的乘积;例:N=(p1^a1)*(p2^a2)*(p3^a3)......其中p1<p2<p3......

    所以当我们求两个很大的数相除时  唯一分解定理是一个不错的选择,不会爆范围

    下面具体说一下怎么求唯一分解定理:

    首先我们需要知道所有的素数:  用埃式算法打表求得:

    void is_prime()
    {
        cnt=0;
        for(int i=2;i<=maxn;i++)
        {
            if(!vis[i])
            {
                prime[cnt++]=i;
                for(int j=i*2;j<=maxn;j+=i) vis[j]=true;
            }
        }
    }

    接下来 就是求pi和ai了,

    void solve(ll n,ll d)
    {
        for(int i=0;i<cnt;i++)
        {
            while(n%prime[i]==0)
            {
                n/=prime[i];
                e[i]+=d;
            }
            if(n==1) return ;
        }
    }

    下面看一道例题:

    题目链接:https://vjudge.net/problem/UVA-10375

    题目大意:用C(p,q)/C(r,s)  最后结果保留5位小数

    思路:这道题不用唯一分解定理就不好做了,阶层相乘很有可能会爆数据范围,总之挺麻烦的,但是用唯一分解定理跟快就能A了  很简单  看代码应该就能明白了

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    using namespace std;
    typedef long long ll;
    const int maxn=1e4+5;
    ll prime[maxn];
    ll e[maxn];
    bool vis[maxn];
    ll cnt;
    void is_prime()
    {
        cnt=0;
        for(int i=2;i<=maxn;i++)
        {
            if(!vis[i])
            {
                prime[cnt++]=i;
                for(int j=i*2;j<=maxn;j+=i) vis[j]=true;
            }
        }
    }
    void solve(ll n,ll d)//n为相乘的数 当为分子时d为1  为分母时d为-1   很好理解 对应指数+1或-1嘛
    {
        for(int i=0;i<cnt;i++)
        {
            while(n%prime[i]==0)
            {
                n/=prime[i];
                e[i]+=d;
            }
            if(n==1) return ;
        }
    }
    int main()
    {
        ll p,q,r,s;
        double ans;
        memset(vis,false,sizeof(vis));
        is_prime();
    //    for(int i=0;i<cnt;i++) cout<<prime[i]<<" ";
    //    cout<<endl;
        while(cin>>p>>q>>r>>s)
        {
            ans=1;
            memset(e,0,sizeof(e));
            for(int i=p;i>=1;i--) solve(i,1);
            for(int i=p-q;i>=1;i--) solve(i,-1);
            for(int i=q;i>=1;i--) solve(i,-1);
            for(int i=r-s;i>=1;i--) solve(i,1);
            for(int i=s;i>=1;i--) solve(i,1);
            for(int i=r;i>=1;i--) solve(i,-1);
            for(int i=0;i<cnt;i++)
                if(e[i]) ans*=pow(prime[i],e[i]);
    
            printf("%.5lf
    ",ans);
        }
    }
    当初的梦想实现了吗,事到如今只好放弃吗~
  • 相关阅读:
    牛客(4) 重建二叉树
    牛客(3)从尾到头打印链表
    牛客(2)字符串替换
    牛客(1)二分查找
    同义词+序列+视图+临时表
    用户+授权
    控制文件+日志文件
    oracle表的基本操作
    Linux(CentOS6.8)配置Redis
    Linux(CentOS6.8)配置ActiveMQ
  • 原文地址:https://www.cnblogs.com/caijiaming/p/10334541.html
Copyright © 2011-2022 走看看