hdu5525

Product

 
 Accepts: 21
 
 Submissions: 171
 Time Limit: 6000/3000 MS (Java/Others)
 
 Memory Limit: 131072/131072 K (Java/Others)
问题描述
给n个数{A}_{1},{A}_{2}....{A}_{n}A1,A2....An,表示N=\prod_{i=1}^{n}{i}^{{A}_{i}}N=i=1niAi。求N所有约数之积。
输入描述
输入有多组数据.
每组数据第一行包含一个整数n.(1\leq n\leq {10}^{5})(1n105)
第二行n个整数{A}_{1},{A}_{2}....{A}_{n}A1,A2....An,保证不全为0.(0\leq {A}_{i}\leq {10}^{5})(0Ai105).
数据保证 \sum n\leq 500000n500000.
输出描述
对于每组数据输出一行为答案对{10}^{9}+7109+7取模的值.
输入样例
4
0 1 1 0
5
1 2 3 4 5
输出样例
36
473272463
本来以为自己不会做这道题,结果,哈哈哈。
就是把N分解成质数,再从里面取数构成约数。
最后推出的公式是(设质数是p1,p2,……pm,每个质数的幂数是bi,Q是(b1+1)*(b2+1)*……*(bn+1)):
p1^(Q*b1/2)*p2*(Q*b2/2)*……*pn(Q*bn/2) ,再加上费马小定理的优化,就可以过了。

以ac的代码:
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
#define N 100010
#define MOD 1000000007

bool isprime[N];
int primenum[N];
int cou;
int primeid[N];
long long int numa[N];

void getprime(){
    memset(isprime,true,sizeof(isprime));
    isprime[0]=false;
    isprime[1]=false;
    cou=0;
    for(int i=2;i<N;i++){
        if(isprime[i]==true){
            primenum[cou++]=i;
            primeid[i]=cou-1;
        }
        for(int j=0;j<cou&&primenum[j]*i<N;j++){
            isprime[i*primenum[j]]=false;
            if(i%primenum[j]==0){
                break;
            }
        }
    }

    return;
}

void add(int num,int a){
    //printf("%d %d\n",num,a);
    for(int j=0;j<cou&&primenum[j]*primenum[j]<=num;j++){
        if(num%primenum[j]==0){
            int tempcou=0;

            while(num%primenum[j]==0){
                tempcou++;
                num=num/primenum[j];
            }
            numa[j]=numa[j]+a*tempcou;
        }
    }
    if(num!=1){
        numa[primeid[num]]+=a;
    }

    return;
}

long long int km(long long int x,long long int y){
    long long int ans=1;

    while(y){
        if(y%2){
            ans=ans*x%MOD;
        }
        y=y/2;
        x=x*x%MOD;
    }

    return ans;
}

int main(){
    int n;
    int tempa;

    getprime();

    while(scanf("%d",&n)!=EOF){
        memset(numa,0,sizeof(numa));
        for(int i=1;i<=n;i++){
            scanf("%d",&tempa);
            add(i,tempa);//printf("wo shi da hao ren\n");
        }

        bool isodd=false;
        long long int q=1;

        for(int i=0;i<cou;i++){
            if(numa[i]%2==1&&isodd==false){
                q=q*((numa[i]+1)/2)%(MOD-1);
                isodd=true;
            }
            else{
                q=q*(numa[i]+1)%(MOD-1);
            }
        }

        long long int ans=1;

        if(isodd==false){//是==,而不是=,因为这个wr了,注意
            for(int i=0;i<cou;i++){
                ans=ans*km(primenum[i],q*(numa[i]/2)%(MOD-1))%MOD;
            }
        }
        else{
            for(int i=0;i<cou;i++){
                ans=ans*km(primenum[i],q*numa[i]%(MOD-1))%MOD;
            }
        }

        //printf("%lld\n",q);
        printf("%lld\n",ans);
    }

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值