Light OJ 1054 - Efficient Pseudo Code

Sometimes it's quite useful to write pseudo codes for problems. Actually you can write the necessary steps to solve a particular problem. In this problem you are given a pseudo code to solve a problem and you have to implement the pseudo code efficiently. Simple! Isn't it? 😃

pseudo code

{

    take two integers n and m

    let p = n ^ m (n to the power m)

    let sum = summation of all the divisors of p

    let result = sum MODULO 1000,000,007

}

Now given n and m you have to find the desired result from the pseudo code. For example if n = 12 and m = 2. Then if we follow the pseudo code, we get

pseudo code

{

    take two integers n and m

    so, n = 12 and m = 2

    let p = n ^ m (n to the power m)

    so, p = 144

    let sum = summation of all the divisors of p

    so, sum = 403, since the divisors of p are 1, 2, 3, 4, 6, 8, 9, 12, 16, 18, 24, 36, 48, 72, 144

    let result = sum MODULO 1000,000,007

    so, result = 403

}

Input

Input starts with an integer T (≤ 5000), denoting the number of test cases.

Each test case will contain two integers, n (1 ≤ n) and m (0 ≤ m). Each of n and m will be fit into a 32 bit signed integer.

Output

For each case of input you have to print the case number and the result according to the pseudo code.

Sample Input

3
12 2
12 1
36 2

Output for Sample Input

Case 1: 403
Case 2: 28
Case 3: 3751

题目大意就是说计算n的m次方的所有因子和,由于n和m的范围是在int范围内,所以不能暴力求解。

首先,将n分解为质数的方的乘积。

例如: \(n = p_{1}^{x_1} * p_{2}^{x_2} * p_{3}^{x_3} * ... * p_{k}^{x_k}\) 其中\(p_x\)为质数。

所以 \(n^m = p_{1}^{x_{1}*m} * p_{2}^{x_{2}*m} * p_{3}^{x_{3}*m} * ... * p_{k}^{x_{k}*m}\).

所以\(n^m\)的所有因子和为:

\(sum = (p_{1}^0 + p_{1}^1 + p_{1}^2 + p_{1}^3 + ... + p_{1}^{x_{1}*m})*(p_{2}^0 + p_{2}^1 + p_{2}^2 + p_{2}^3 + ... + p_{2}^{x_{2}*m})*(p_{3}^0 + p_{3}^1 + p_{3}^2 + p_{3}^3 + ... + p_{3}^{x_{3}*m})* ... *(p_{k}^0 + p_{k}^1 + p_{k}^2 + p_{k}^3 + ... + p_{k}^{x_{k}*m})\)

到达此步后我们就可以用两种方法直接计算出\((p_{k}^0 + p_{k}^1 + p_{k}^2 + p_{k}^3 + ... + p_{k}^{x_{k}*m})\)
一项的解

解法一

通过等比数列前n项和公式,在通过逆元,即可算出这一项的和

代码如下:

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
vector<ll> prim;
const ll mod = 1000000007;

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

void get_prim()
{
    ll arr[100000];
    memset(arr, false, sizeof(arr));
    for(ll i=2; i<100000; ++ i)
    {
        if(arr[i] == false)
        {
            prim.push_back(i);
            for(ll j=i*i; j<100000; j+=i)
                arr[i] = true;
        }
    }
}

void extgcd(ll a, ll b, ll &x, ll &y)
{
    if(b)
    {
        extgcd(b, a % b, y, x);
        y -= (a / b) * x;
    }
    else
    {
        x = 1, y = 0;
    }
}

vector<pair<ll, ll> >res;

void solve(int cases)
{
    ll n, m;
    cin >> n >> m;
    res.clear();
    for(int i=0; prim[i]*prim[i] <= n; ++ i)
    {
        ll s = 0;
        while(n % prim[i] == 0)
            n /= prim[i], s ++;
        if(s != 0)
            res.push_back(make_pair(prim[i], s*m));
    }
    if(n != 1)
        res.push_back(make_pair(n, m));

    ll ans = 1;
    for(int i=0; i<res.size(); ++ i)
    {
        ll x, y;
        extgcd(res[i].first-1, mod, x, y);
        while(x < 0)
            x += mod;
        ans = (ans * (x * ((quick_pow(res[i].first, res[i].second+1)-1 + mod)%mod) % mod)) % mod;
    }
    cout << "Case " << cases << ": ";
    cout << ans << endl;
}

int main()
{
    ios::sync_with_stdio(false);
    //freopen("out.txt", "w", stdout);
    get_prim();

    int t;
    cin >> t;
    for(int i=1; i<=t; ++ i)
        solve(i);
    return 0;
}


解法二

折半递归计算

对于\(p_{k}^0 + p_{k}^1 + p_{k}^2 + p_{k}^3 + ... + p_{k}^{x_{k}*m}\)

  • 如果\(x_{k}*m\)为奇数。则这一项可以写成这样\(p_{k}^0 + p_{k}^1 + p_{k}^2 + p_{k}^3 + ... + p_{k}^{x_{k}*m/2-1} + p_{k}^{x_{k}*m/2}*(p_{k}^0 + p_{k}^1 + p_{k}^2 + p_{k}^3 + ... + p_{k}^{x_{k}*m/2-1})\),然后合并同类项可得:\((p_{k}^{x_{k}*m}+1)*(p_{k}^0 + p_{k}^1 + p_{k}^2 + p_{k}^3 + ... + p_{k}^{x_{k}*m/2-1})\),然后依次递归下去
  • 如果\(x_{k}*m\)为偶数。则可写成\(p_{k}^0 + p_{k}^1 + p_{k}^2 + p_{k}^3 + ... + p_{k}^{x_{k}*m/2-1} + p_{k}^{x_{k}*m/2} + p_{k}^{x_{k}*m/2+1}*(p_{k}^0 + p_{k}^1 + p_{k}^2 + p_{k}^3 + ... + p_{k}^{x_{k}*m/2-1})\),然后合并同类项可得:\(p_{k}^{x_{k}*m/2} + (p_{k}^{x_{k}*m/2+1}+1)*(p_{k}^0 + p_{k}^1 + p_{k}^2 + p_{k}^3 + ... + p_{k}^{x_{k}*m/2-1})\),然后依次递归下去

递归完毕后就可以求得这一项的和。

代码如下:

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
vector<ll> prim;
const ll mod = 1000000007;

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

void get_prim()
{
    ll arr[100000];
    memset(arr, false, sizeof(arr));
    for(ll i=2; i<100000; ++ i)
    {
        if(arr[i] == false)
        {
            prim.push_back(i);
            for(ll j=i*i; j<100000; j+=i)
                arr[i] = true;
        }
    }
}

ll cou(ll x, ll n)
{
    if(n == 0)
        return 1;

    if(n & 1)
        return ((quick_pow(x, (n+1)/2) + 1) * cou(x, n/2)) % mod;
    else
        return (quick_pow(x, n/2) + (quick_pow(x, n/2+1) + 1) * cou(x, (n-2)/2)) % mod;
}

vector<pair<ll, ll> >res;

void solve(int cases)
{
    ll n, m;
    cin >> n >> m;
    res.clear();
    for(int i=0; prim[i]*prim[i] <= n; ++ i)
    {
        ll s = 0;
        while(n % prim[i] == 0)
            n /= prim[i], s ++;
        if(s != 0)
            res.push_back(make_pair(prim[i], s*m));
    }
    if(n != 1)
        res.push_back(make_pair(n, m));

    ll ans = 1;
    for(int i=0; i<res.size(); ++ i)
        ans = (ans * cou(res[i].first, res[i].second)) % mod;
    cout << "Case " << cases << ": ";
    cout << ans << endl;
}

int main()
{
    ios::sync_with_stdio(false);
    //freopen("out.txt", "w", stdout);
    get_prim();

    int t;
    cin >> t;
    for(int i=1; i<=t; ++ i)
        solve(i);
    return 0;
}

posted @ 2017-05-13 23:55  aiterator  阅读(218)  评论(0编辑  收藏  举报