Codeforces 615D Multipliers

题目大意

给出一个数 n n n的质因数分解: n = p 1 × p 2 × ⋯ × p m n = p_1 \times p_2 \times \cdots \times p_m n=p1×p2××pm
n n n的所有因数的乘积,模 1 0 9 + 7 10^9+7 109+7

时间限制

2s

数据范围

m ≤ 2 × 1 0 5 m \le 2\times 10^5 m2×105
p i ≤ 2 × 1 0 5 p_i\le 2\times 10^5 pi2×105,且保证 p i p_i pi是质数

题解

n n n非常大,不可能计算出来,更加不可能枚举 n n n的因数,
换一种思路,就是考虑每个质因数对答案的贡献。
我们不妨将 n n n表示成 p i k i p_i^{k_i} piki这种形式。
n = Π i = 1 m p i k i n = \Pi_{i = 1} ^ m p_i ^ {k_i} n=Πi=1mpiki
显然 n n n的因数个数就有 S = Π i = 1 m k i + 1 S=\Pi_{i = 1}^m k_i+1 S=Πi=1mki+1

现在考虑一个质因数 p i p_i pi对答案的贡献,
它自身可以组成的因数有: p i 0 , p i 1 , ⋯   , p i k i p_i^0,p_i^1,\cdots,p_i^{k_i} pi0,pi1,,piki
它们出现的次数是 S k i + 1 \frac{S}{k_i+1} ki+1S
因此,总的贡献就是 ( Π j = 0 k i p i j ) S k i + 1 (\Pi_{j = 0}^{k_i} p_i^j)^{\frac{S}{k_i+1}} (Πj=0kipij)ki+1S
根据欧拉公式,我们知道指数上的模数为 1 0 9 + 6 10^9+6 109+6,显然它不一定存在逆元,所以在这里需要特殊维护一下。

Code

//#pragma GCC optimize (2)
//#pragma G++ optimize (2)
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <vector>
#include <queue>
#define G getchar
#define ll long long
using namespace std;

int read()
{
    char ch;
    for(ch = G();(ch < '0' || ch > '9') && ch != '-';ch = G());
    int n = 0 , w;
    if (ch == '-')
    {
        w = -1;
        ch = G();
    } else w = 1;
    for(;'0' <= ch && ch <= '9';ch = G())n = (n<<1)+(n<<3)+ch-48;
    return n * w;
}

const int N = 200005;
const int mo = 1000000007;

int n , t;
int a[N] , nxt[N];
ll ans , s[N];

ll ksm(ll x , ll y)
{
    ll s = 1;
    for (; y ; )
    {
        if (y & 1) s = s * x % mo;
        x = x * x % mo;
        y = y >> 1;
    }
    return s;
}

int main()
{
    //freopen("b.in","r",stdin);
    //freopen("b.out","w",stdout);
    n = read();
    ans = 1;
    for (int i = 0 ; i < n ; i++)
    {
        t = read();
        a[t]++;
    }
    s[N - 1] = 1;
    for (int i = 1 ; i < N ; i++)
        if (a[i])
        {
            if (s[a[i] + 1] == 0)
            {
                int x = N - 1;
                for (; nxt[x] ;)
                {
                    s[x] = s[x] * (a[i] + 1) % (mo - 1);
                    x = nxt[x];
                }
                nxt[x] = a[i] + 1;
                if (x != N - 1) s[a[i] + 1] = s[x] * x % (mo - 1); else s[a[i] + 1] = s[x];
                s[x] = s[x] * (a[i] + 1) % (mo - 1);
            }
            else
            {
                int x = N - 1;
                for (; x ;)
                {
                    s[x] = s[x] * (a[i] + 1) % (mo - 1);
                    x = nxt[x];
                }
            }
        }

    for (int i = 1 ; i < N ; i++)
        if (a[i]) ans = ans * ksm(i , (ll)a[i] * (a[i] + 1) / 2 % (mo - 1) * s[a[i] + 1] % (mo - 1)) % mo;
    printf("%lld\n", ans);
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值