hdu1215 正整数唯一分解定理应用

B - (例题)因子和

Crawling in process... Crawling failed Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u

Submit Status

Description

七夕节那天,月老来到数字王国,他在城门上贴了一张告示,并且和数字王国的人们说:"你们想知道你们的另一半是谁吗?那就按照告示上的方法去找吧!"
人们纷纷来到告示前,都想知道谁才是自己的另一半.告示如下:



数字N的因子就是所有比N小又能被N整除的所有正整数,如12的因子有1,2,3,4,6.
你想知道你的另一半吗?
 

Input

输入数据的第一行是一个数字T(1<=T<=500000),它表明测试数据的组数.然后是T组测试数据,每组测试数据只有一个数字N(1<=N<=500000).
 

Output

对于每组测试数据,请输出一个代表输入数据N的另一半的编号.
 

Sample Input

3 2 10 20
 

Sample Output

1 8 22
题目大意:给你一个数n,让你求他的所有因子和,除了他本身
思路分析:暴力也可以做,姿势好就行,O(sqrt(n))的复杂度,即求因子,扫到sqrt(n)就可以,要特别注意i*i==n的情况
标准算法则是应用正整数唯一分解定理,将n唯一分解后,它的所有因子和实际上就是(a1^0+a2^0...)(a2^0....)......
即各种排列组合的和,又因为不包含本身,所以最后减去n;
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include<algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn=1000;//
bool vis[maxn];
ll prime[maxn/10];
int tot;
void getprime()//因为n的范围是1e14,打表只需要打到sqrt(n)即可,最多只可能有一个素因子大于sqrt(n),最后特判一下即可;
{
    memset(vis,true,sizeof(vis));
    tot=0;
    for(ll i=2;i<maxn;i++)
    {
        if(vis[i])
        {
        prime[tot++]=i;
        for(ll j=i*i;j<maxn;j+=i)
        {
            vis[j]=false;
        }
        }
    }
}
/*void Eulerprime()
{
    memset(vis,true,sizeof(vis));
    int tot=0;
    for(int i=2;i<maxn;i++)
    {
        if(vis[i]) prime[tot++]=i;
        for(int j=0;j<tot&&prime[j]*i<maxn;j++)
        {
            vis[i*prime[j]]=false;
            if(i%prime[j]==0) break;
        }
    }
}*/
int a[1000],b[1000];
int cnt=0;
void sbreak(ll n)//正整数唯一分解
{
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    cnt=0;
    for(int i=0;prime[i]*prime[i]<=n;i++)
    {
        if(n%prime[i]==0)
        {
            a[cnt]=prime[i];
            while(n%prime[i]==0)
            {
                b[cnt]++;
                n/=prime[i];
            }
            cnt++;
        }
    }
    if(n!=1)
    {
        a[cnt]=n;
        b[cnt]=1;
        cnt++;//为了使两种情况分解后素因子下标都是0~cnt-1;
    }
}
int pow_mod(int m,int n)
{
    ll pw=1;
    while(n)
    {
        if(n&1) pw*=m;
        m*=m;
        n/=2;
    }
    return pw;
}
int kase;
int main()
{
    int T;
    ll n;
    getprime();
    scanf("%d",&T);
    kase=0;
    while(T--)
    {
        scanf("%lld",&n);
        sbreak(n);
        ll sum=1;
        for(int i=0;i<cnt;i++)
        {
            ll cur=0;
            for(int j=0;j<=b[i];j++)
            {
                cur+=pow_mod(a[i],j);
            }
            sum*=cur;
        }
         printf("%lld
",sum-n);
    }
}
View Code
原文地址:https://www.cnblogs.com/xuejianye/p/5674954.html