【唯一分解定理 && 状态压缩 && 组合数学】LightOJ

来源:互联网 发布:行业数据查询 编辑:程序博客网 时间:2024/05/21 11:15

Problem Description

long long pairsFormLCM( int n ) {
long long res = 0;
for( int i = 1; i <= n; i++ )
for( int j = i; j <= n; j++ )
if( lcm(i, j) == n ) res++; // lcm means least common multiple
return res;
}
输入n让你实现这个程序,求出有多少对lcm(i,j) == n。

思路:

参考了一个很好的博客
核心点:N可以唯一分解成有限个质数的乘积N=P1^a1*P2^a2*P3^a3……Pn^an
令a = p1^e1 * p2^e2
令b = p1^e3 * p2^e4
gcd(a, b) = p1^min(e1, e3) * p2^min(e2, e4)
lcm(a, b) = a*b/gcd(a,b) = p1^max(e1, e3) * p2^max(e2, e4)
参考别人的思路:比如24=2^3*3^1:
(1)如果一个数完整地包含了3^1但是没有完整地包含2^3(一个数x完整地包含某个质因数p及其出现的次数t,指x可以被p^t整除),比如3,6,12,那么另一个数必须完整地包含2^3,比如8,24。那么此时有六种组合(3,8),(3,24),(6,8),(6,24),(12,8),(12,24)
(2)若一个数完整地包含2^3但是没有完整地包含3^1,比如8,那么另一个数必须完整地包含3^1,比如3,6,12,24,此时有4个。
(3)若一个数完整地包含了2^3和3^1,比如24,那么另一个数有(3+1)*(1+1)种可能,即1,2,3,4,6,8,12,24。
(4)若一个数既没有完整的包含2^3也没有完整地包含3^1,比如1,2,4,那么另一个数必须为24,此时有3种。
到此为止,你发现除了(24,24)这种组合只在(3)中出现一次,其他情况均出现2次。若上面的总数为t,那么答案为(t+1)/2。

#include<bits/stdc++.h>using namespace std;#define nn 10000005//根号最大值就可以bool vis[nn];//vis[i] = 0代表i是素数,否则不是int prime[nn / 10];//保存1-(nn-5)范围内的素数,个数为mlong long n, m;int a[nn / 10], b[nn / 10], t;void Is_prime()//素数筛法{    long long i, j;    memset(vis, 0, sizeof(vis));    vis[1] = vis[0] = 1;    m = 0;    for(i = 2; i <= nn - 5; i++)    {        if(!vis[i])        {            prime[m++] = i;            for(j = 2*i; j <= nn - 5; j = j + i)                vis[j] = 1;        }    }}long long solve(){    long long x, y, i, j;    long long ans = 0;    for(i = 0; i < 1<<t; i++)//分解出t个素数,(1<<t)所有可能的情况    {        x = y = 1;        for(j = 0; j < t; j++)        {            if(i&(1<<j)) x *= b[j] + 1;//包含n所以要+1,二进制为1对应的质素 组成有x个不同的数            else y *= b[j];//二进制为0对应的质素 组成有y个不同的数        }        ans += x * y;//组合起来的情况为x*y    }    return (ans + 1) / 2;//返回所有情况}int main(){    int T, Case = 1;    scanf("%d", &T);    Is_prime();    while(T--)    {        scanf("%lld", &n);        long long mm = sqrt(n);        if(mm * mm > n) mm--;//可加可不加,加比较保险,防止出意外        t = 0;        for(int i = 0; i < m && prime[i] <= mm; i++)//质因数分解        {            if(n % prime[i] == 0)            {                a[t] = prime[i];                b[t] = 0;                while(n % prime[i] == 0)                {                    b[t]++;                    n /= prime[i];                }                t++;            }        }        if(n != 1) {            a[t] = n;            b[t++] = 1;        }//        printf("Case %d: %lld\n", Case++, solve());    }    return 0;}
阅读全文
0 0