Codeforces 615D Multipliers (Round #338 (Div. 2) D题)

题意

  • 给你一个数n的所有分解质因数的质因子,问你这个数全部的因子乘积模1e9+7得几

思路

  • 变量:p[i]表示第i种质因子,num[i]表示第i种质因子有多少个
  • 我们基本的思路就是,ans = ans * p[i] ^ k[i] 其中k[i]表示第i种质因子,在最后乘积中用了多少次,然后用快速幂就可以搞定
  • 那么,我们先来解决k[i]等于多少
  • 首先第一个结论,n的所有因子数为d = d * (num[i] + 1) ,这个很好证明,就是说第i种质因子可以选用0个到num[i]个,所以简单乘法原理就可以得到上式
  • 然后,对于第i种质因子,假设它选t个,然后其它质因子就可以选择d1[i] = d1[i] * (num[j] + 1) (j != i)种, 第i种质因子选t个时,就会用到t * d1[i]个,因为t可以取1 ~ num[i],因此k[i] = (num[i] * (num[i] + 1) ) / 2 * d1[i]
  • 这样我们就解决了一半的问题,剩下的问题是k[i] 很大, p[i] ^ k[i] mod m等于多少?
  • 根据小费马定理x ^ (p-1) = 1 (mod p),所以可知,x ^ y = x ^ (y mod (p-1)) (mod p)
  • 最后一个问题,由于我们怎么很快算出k[i],由于m-1不是质数了,所以把d算出来之后再乘(num[i] + 1)的逆元是不可以的了,我先想到用线段树来解决问题。。。有点做复杂了
  • 其实,我们换个角度看 p[i] ^ k[i] = (p[i] ^ ((num[i] * (num[i] + 1) ) / 2) ) ^ d1[i]
  • 然后我们在迭代的过程中,交换一下乘的次序,就很容易解决问题,详细的见代码吧~比较简单

实现

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define mp make_pair
#define pb push_back
#define fi first
#define se second
const int inf = 0x3f3f3f3f;
const ll mod = 1e9+7;
const double eps = 1e-8;
int m;

ll mod_pow(ll x, ll n){
    ll ret = 1;
    while (n > 0){
        if (n & 1) ret = ret * x % mod;
        x = x * x % mod;
        n>>=(ll)1;
    }
    return ret;
}

const int maxn = 200005;
int p[maxn],num[maxn];
int mark[maxn];

int main(){
    //freopen("out.txt","w",stdout);
    cin>>m;
    int now = 1;
    for (int i=0;i<m;i++){
        int tmp;
        scanf("%d",&tmp);
        if (mark[tmp] != 0){
            num[mark[tmp]]++;
        }
        else{
            mark[tmp] = now;
            p[now] = tmp;
            num[now]++;
            now++;
        }
    }
    //sum是累乘的指数 
    ll sum = 1;
    ll ans = 1;

    for (int i=1;i<now;i++)
    {
        ll tmp = mod_pow((ll)p[i],(ll)num[i] * (ll)(num[i] + 1) / (ll)2);
        ans = (mod_pow(ans,(ll)(num[i] + 1)) * mod_pow(tmp, sum)) % mod;
        sum = (sum * (ll)(num[i] + 1)) % (mod - 1); 
    }
    cout << ans <<"\n";


    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值