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;
}