zoukankan      html  css  js  c++  java
  • 唯一分解定理

    唯一分解定理又称为算数基本定理,基本内容是:

    每个大于1的自然数,要么本身就是质数,要么可以写为2个或以上的质数的积,而且这些质因子按大小排列之后,写法仅有一种方式。

    用另一种方法表示就是:

    对于任何一个大于1的正整数,都存在一个标准的分解式:  N=p1^a1 * p2^a2*···*pn^an;(其中一系列an为指数,pn为质数)

    此定理表明:任何一个大于 1 的正整数都可以表示为素数的积。

    有这样几个式子:

    设F(n)代表n的正因子的数量,则F(n)=(a1+1)*(a2+1)*(a3+1)*······*(an+1);

    设G(n)代表n的正因子的和,则G(n)=(1+p1^2+p1^3+...+p1^a1)*(1+p2^2+p2^3+...p2^a2)*....*(1+pn^1+pn^2+...+pn^an)=

    获得一个数正因子数量的代码:

    primel [ ]是素数表

     1 ll getfac(ll x)
     2 {
     3     ll ans=1;
     4     for(int i=1;i<=cnt&&primel[i]<=x;i++)
     5     {
     6         ll sum=0;//当前质因数的幂指数 
     7         while(x%primel[i]==0)//当是这个数的因子时 
     8         {
     9             sum++;
    10             x/=primel[i];
    11         }
    12         ans*=(sum+1);//应用定理的结论 
    13     }
    14     if(x>1)//当搜索不到的时候,如果这个数最后大于一,那么这个最后结果肯定是素数,并且指数是1 
    15     ans*=2;
    16     return ans;
    17 }

    来看一个应用此定理的例题:

    链接:Light OJ 1341 Aladdin and the Flying Carpet

    此题的题意就是,给定一个矩形(非正方形)的面积 a,求可以分解的长*宽有多少组,且任意一条边不能小于b,不能重复(4*3和3*4重复)。

    即求一个数可以分解为多少个正因数相乘,想到唯一分解定理,用它把所有可能的因子找出后,再除以2,在把小于b的因子暴力去除。

    看代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 using namespace std;
     5 typedef long long ll;
     6 const int maxn=1e6+20;
     7 int primel[maxn];
     8 bool isp[maxn];
     9 int cnt;
    10 void makel()//欧拉筛打印素数表 
    11 {
    12     cnt=0;
    13     memset(isp,true,sizeof(isp));
    14     for(int i=2;i<maxn;i++)
    15     {
    16         if(isp[i])
    17         primel[++cnt]=i;
    18         for(int j=1;j<=cnt;j++)
    19         {
    20             if(i*primel[j]>maxn)
    21             break;
    22             isp[i*primel[j]]=false;
    23             if(i%primel[j]==0)
    24             break;
    25         }
    26     }
    27 }
    28 ll getfac(ll x)//唯一分解定理 
    29 {
    30     ll ans=1;
    31     for(int i=1;i<=cnt&&primel[i]*primel[i]<=x;i++)
    32     {
    33         ll sum=0; 
    34         while(x%primel[i]==0) 
    35         {
    36             sum++;
    37             x/=primel[i];
    38         }
    39         ans*=(sum+1);
    40     }
    41     if(x>1) 
    42     ans*=2;
    43     return ans;
    44 }
    45 int main()
    46 {
    47     int t;
    48     int cas=0;
    49     ll a,b;
    50     cin>>t;
    51     makel();
    52     while(t--)
    53     {
    54         scanf("%lld%lld",&a,&b);
    55         if(a<b*b)//不可能分解为比b大的数相乘 
    56         {
    57         printf("Case %d: 0
    ",++cas);
    58         continue;
    59         }
    60         ll count=getfac(a)/2;//不能重复 
    61         for(int i=1;i<b;i++)//去除小于b的因子 
    62         {
    63             if(a%i==0)
    64             count--;
    65         }
    66         printf("Case %d: %lld
    ",++cas,count);
    67     }
    68     return 0;
    69 }

    再看一个题:

    这个题运用了分解质因子和的公式(原理)。

    链接:LightOJ 1136 Sigma Function

    这个题其实就是求1~n所有的数中,可分解为质因子的和为偶数的数有多少个。

    这个其实就是那个和的公式(结论)。

    把上面的结论搬下来,那个公式G(n)=(1+p1^2+p1^3+...+p1^a1)*(1+p2^2+p2^3+...p2^a2)*....*(1+pn^1+pn^2+...+pn^an);

    就是要让它等于偶数,分析一下,这首先是乘积式,如果要让乘积为偶数,那么每一项就是偶数,可是这样的话pi如果偶数那么所有pi为偶数的G(n)都是奇数(pi^ai一定为偶,再加个1),在剩下的情况中,得分很多情况,定TLE。于是想反面,求多少个G(n)为奇数,再减去。

    如果要让和为奇数,想奇*偶=偶,奇*奇=奇,偶*偶=偶,于是只要让每一项(1+pi^ai)为奇数即可,如果p[i] = 2;,则其和一定为奇数(2的幂次和为偶+1),除了2以外,素数都是奇数,所以 (p[i]^0 + p[i]^1 +.....+ p[i]^e[i])要满足是奇数的话e[i]一定是偶数(首先奇数任何次幂仍为奇数,奇+奇=偶两两组合后一定还剩一个奇数,然后偶+奇=奇),如果 n 是一个平方数,那么他的约数和一定是奇数,如果2*n是平方数,他的约数和也是奇数。

    代码如下:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cmath>
     4 using namespace std;
     5 typedef long long ll;
     6 int main()
     7 {
     8     int t,cas=0;
     9     ll n;
    10     cin>>t;
    11     while(t--)
    12     {
    13         scanf("%lld",&n);
    14         ll ans;
    15         ans=n-(ll)sqrt(n)-(ll)sqrt(n/2);
    16         printf("Case %d: %lld
    ",++cas,ans);
    17     }
    18     return 0;
    19 }
  • 相关阅读:
    字符串排序
    螺旋方阵
    Palindrome(最长回文串manacher算法)O(n)
    最长回文串(manacher算法)
    hdu 1236 1.3.2排名
    hdu 1062 Text Reverse
    VS2010/MFC对话框四:为控件添加消息处理函数
    VS2010/MFC对话框三:创建对话框类和添加控件变量
    VS2010/MFC对话框二:为对话框添加控件)
    VS2010/MFC对话框一:创建对话框模板和修改对话框属性
  • 原文地址:https://www.cnblogs.com/theshorekind/p/12704405.html
Copyright © 2011-2022 走看看