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=px11∗px22∗px33∗...∗pxkkn=px11∗px22∗px33∗...∗pxkk 其中pxpx为质数。
所以 nm=px1∗m1∗px2∗m2∗px3∗m3∗...∗pxk∗mknm=px1∗m1∗px2∗m2∗px3∗m3∗...∗pxk∗mk.
所以nmnm的所有因子和为:
sum=(p01+p11+p21+p31+...+px1∗m1)∗(p02+p12+p22+p32+...+px2∗m2)∗(p03+p13+p23+p33+...+px3∗m3)∗...∗(p0k+p1k+p2k+p3k+...+pxk∗mk)sum=(p01+p11+p21+p31+...+px1∗m1)∗(p02+p12+p22+p32+...+px2∗m2)∗(p03+p13+p23+p33+...+px3∗m3)∗...∗(p0k+p1k+p2k+p3k+...+pxk∗mk)
到达此步后我们就可以用两种方法直接计算出(p0k+p1k+p2k+p3k+...+pxk∗mk)(p0k+p1k+p2k+p3k+...+pxk∗mk)
一项的解
解法一
通过等比数列前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;
}
解法二
折半递归计算
对于p0k+p1k+p2k+p3k+...+pxk∗mkp0k+p1k+p2k+p3k+...+pxk∗mk
- 如果xk∗mxk∗m为奇数。则这一项可以写成这样p0k+p1k+p2k+p3k+...+pxk∗m/2−1k+pxk∗m/2k∗(p0k+p1k+p2k+p3k+...+pxk∗m/2−1k)p0k+p1k+p2k+p3k+...+pxk∗m/2−1k+pxk∗m/2k∗(p0k+p1k+p2k+p3k+...+pxk∗m/2−1k),然后合并同类项可得:(pxk∗mk+1)∗(p0k+p1k+p2k+p3k+...+pxk∗m/2−1k)(pxk∗mk+1)∗(p0k+p1k+p2k+p3k+...+pxk∗m/2−1k),然后依次递归下去
- 如果xk∗mxk∗m为偶数。则可写成p0k+p1k+p2k+p3k+...+pxk∗m/2−1k+pxk∗m/2k+pxk∗m/2+1k∗(p0k+p1k+p2k+p3k+...+pxk∗m/2−1k)p0k+p1k+p2k+p3k+...+pxk∗m/2−1k+pxk∗m/2k+pxk∗m/2+1k∗(p0k+p1k+p2k+p3k+...+pxk∗m/2−1k),然后合并同类项可得:pxk∗m/2k+(pxk∗m/2+1k+1)∗(p0k+p1k+p2k+p3k+...+pxk∗m/2−1k)pxk∗m/2k+(pxk∗m/2+1k+1)∗(p0k+p1k+p2k+p3k+...+pxk∗m/2−1k),然后依次递归下去
递归完毕后就可以求得这一项的和。
代码如下:
#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;
}
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(四):结合BotSharp
· 一个基于 .NET 开源免费的异地组网和内网穿透工具
· 《HelloGitHub》第 108 期
· Windows桌面应用自动更新解决方案SharpUpdater5发布
· 我的家庭实验室服务器集群硬件清单