【发布时间】:2020-09-26 20:34:39
【问题描述】:
您将获得N 一对数字n、k。对于每一对,计算P 的除数。
P = k^n * (1 + 2 + 3 + ... + k)
从nr_div_huge.in 读取N,然后读取N 对n and k。在输出文件nr_div_huge.out 中,每一行都写着每对P 的除数。因为它可能很大,所以会以 1.000.000.007 为模显示。
- 1≤N≤15.000
- 1≤k,n≤1.000.000.000
- 内存限制:0.1MB
- 时间限制:0.2s
例子:
nr_div_huge.in
2
2 3
4 4
nr_div_huge.out
8
20
说明:
对于第一对 P=54 和 54 有 8 个除数。 第二对 P=2560 和 2560 有 20 个除数。
这是我的代码:
#include <iostream>
#include <fstream>
#define MOD 1000000007
using namespace std;
ifstream fin ("nr_div_huge.in");
ofstream fout("nr_div_huge.out");
bool sieve[30000];
long long int prime[3000];
int N, k, n, r, P;
//making the Sieve of Eratosthenes have in the `prime` array the prime numbers up to 30000
void Erat()
{
int r=0;
sieve[0]=sieve[1]=1;
for(int i=2; i*i<=30000; i++)
if(sieve[i]==0)
for(int j=2; j<=30000/i; j++)sieve[i*j]=1;
for(int i=1; i<=30000; ++i)
if(!sieve[i])prime[++r]=i;
}
//finding the numbers of divisors with Euler formula
int divisors(unsigned int n, unsigned int power)
{
int r=0, d, p, nr=1;
d=prime[++r];
while(n>1)
{
p=0;
while(n%d==0)
{
p++;
n/=d;
}
if(d==2 && p>0)
nr=(1LL*nr*(p*power))%MOD;
else if(p>0)
nr=(1LL*nr*(p*power+1))%MOD;
if(prime[r+1]==0)d++;
else d=prime[++r];
if(d*d>n)d=n;
}
return nr;
}
/*
I've transformed the formula P = k^n * (1 + 2 + 3 + ... +k) into P= k^(n+1)*(k+1)/2
Also, I've used this property:
If we have 2 numbers a and b, which are co-prime numbers, a will have n divisors and b m divisors,
the (a*b) number will have m*n divisors.
*/
int NrP(long long int n, long long int k)
{
unsigned long long int power=1,nrdk1,nrdkn,res=0;
nrdk1=divisors(k+1,1);
nrdkn=divisors(k,n+1);
res=(1LL*nrdk1*nrdkn)%MOD;
return res;
}
int main()
{
Erat();
fin>>N;
for(int i=1; i<=N; i++)
{
fin>>n>>k;
fout<<NrP(n,k)<<'\n';
}
return 0;
}
算法说明:
我一开始就对 Eratosthenes 进行筛选,以使 prime 数组中的素数达到 30000。为了更快地计算1 + 2 + 3 + ... + k 的总和,我使用公式(k*(k+1))/2 并且P 变为(k^(n+1) * (k+1))/2。由于k 和k+1 是互质的,那么k^(n+1) 和k+1 也将是互质的,其中一个是偶数。为了消除/2,我将偶数相除。因为数字是互质数,所以除数是n*m,其中n是k^(n+1)的除数,m是k+1的除数。
为了计算除数的个数,我使用了欧拉公式:
n = p1^e1 * p2^e2 * … * pk^ek - prime factorization
number of divisors = (e1 + 1) * (e2 + 1) * ... * (ek + 1)
如何加快解决速度?或者有没有更快的解决方案?
【问题讨论】:
-
"给定 N 对数 n k。对于每一对,计算下一个数的除数。"能否请您发布一个包含 2 个小数字的示例?
-
你能添加一个简单的英文描述你的算法吗?我不太明白发生了什么事。如果你从字面上计算
k^n的值,结果数字将有 10^9 位十进制数字,并且绝对不适合 long long。