首先,我们要先知道一个定理,任意一个自然数都可以分解为素数之积(素数不再分解)
当我们对这条式子扩展到二维的时候:
当我们对这条式子扩展到n维的时候:
那么其对应的自然N的n次方的约数个数为:
代码实现:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 1e6 + 10;
/*素数表*/
vector<int> ps;
bool is[40010];
void init() {
fill(is, is + 40010, 1);
ps.clear();
is[0] = is[1] = false;
for(int i = 2; i < 40010; ++i) {
if(is[i]) {
for(int j = i + i; j < 40010; j += i)is[j] = false;
}
}
for(int i = 2; i < 40010; ++i) {
if(is[i])ps.push_back(i);
}
}
/* n的P次方的因数的个数 */
ll CC(ll n, ll p=1) {
ll res = 1;
/*ps[idx]*ps[idx]<=n 的设置原理 : 任何一个合数都可以分解为比这个合数小的素数之积*/
/* 当ps大于分界线时 n/ps整除的结果 可能有两种情况:
一种是素数(那么它必定小于分界线,所以在之前就被计算过了)
另一种是合数(也小于分界线), 又合数可以分解为比它本身小的素数积,那么他也一定被计算过了*/
for(int idx = 0; ps[idx]*ps[idx] <= n && idx < ps.size(); ++idx) {
if(n % ps[idx] == 0) {
int cnt = 0;
while(n % ps[idx] == 0) {
cnt++;
n /= ps[idx];
}
res *= (1 + cnt * p);
}
}
// printf("\n最后一个素数 %lld\n", n);
/* 相当于cnt等于1的情况,并且此时的n是一个素数 */
/* 即最后一项为n^p n为最后一个素数*/
if(n > 1)res *= (1 + 1 * p);
return res;
}
相关题目:
http://acm.hdu.edu.cn/showproblem.php?pid=1492
给定一个特殊的数,这个数的约数只有2,3,5,7这几个素数,我们只需要将素数表设置为2,3,5,7就行
AC code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 1e6 + 10;
vector<int> ps;
ll CC(ll n, ll p=1) {
ll res = 1;
/*ps[idx]*ps[idx]<=n 的设置原理 : 任何一个合数都可以分解为比这个合数小的素数之积*/
/* 当ps大于分界线时 n/ps整除的结果 可能有两种情况:
一种是素数(那么它必定小于分界线,所以在之前就被计算过了)
另一种是合数(也小于分界线), 又合数可以分解为比它本身小的素数积,那么他也一定被计算过了*/
for(int idx = 0; ps[idx]*ps[idx] <= n && idx < ps.size(); ++idx) {
if(n % ps[idx] == 0) {
int cnt = 0;
while(n % ps[idx] == 0) {
cnt++;
n /= ps[idx];
}
res *= (1 + cnt * p);
}
}
// printf("\n最后一个素数 %lld\n", n);
/* 相当于cnt等于1的情况,并且此时的n是一个素数 */
if(n > 1)res *= (1 + 1 * p);
return res;
}
int main() {
ll n;
ps.push_back(2);ps.push_back(3);ps.push_back(5);ps.push_back(7);
while(scanf("%lld", &n) && n) printf("%lld\n",CC(n));
return 0;
}
相关题目:
链接:https://www.nowcoder.com/acm/contest/90/F
来源:牛客网
题目描述
给定n,求1/x + 1/y = 1/n (x<=y)的解数。(x、y、n均为正整数)
输入描述:
在第一行输入一个正整数T。
接下来有T行,每行输入一个正整数n,请求出符合该方程要求的解数。
(1<=n<=1e9)
输出描述:
输出符合该方程要求的解数。
由1/x+1/y=1/n,可推得:x∗n+y∗n=x∗y,进一步可推得:x∗y−x∗n−y∗n+n^2=n^2,即:(x−n)(y−n)=n^2。
题目要计算满足x≤y的解的个数。那么,从式子(x−n)(y−n)=n^2可以看出,(x−n)(y−n)相乘为n^2,即只要满足
n^2 %(x−n)=0,n^2 %(y−n)=0就行。也就是,只要(x−n)和(y−n)为n^2的因子且x≤y就行了。
f(n)为算出n的正因子数,答案为两个因子之积且一个因子小于等于另一个因子
所求答案即为(f(n^2)+1)/2。加1的原因是因为x与y可以相等所以(x-n)与(y-n)也可以相等结果为n,所以n这个约数要算两次
AC code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 1e6 + 10;
vector<int> ps;
bool is[40010];
void init() {
fill(is, is + 40010, 1);
ps.clear();
is[0] = is[1] = false;
for(int i = 2; i < 40010; ++i) {
if(is[i]) {
for(int j = i + i; j < 40010; j += i)is[j] = false;
}
}
for(int i = 2; i < 40010; ++i) {
if(is[i])ps.push_back(i);
}
}
/* n的P次方的因数的个数 */
ll CC(ll n, ll p=1) {
ll res = 1;
/*ps[idx]*ps[idx]<=n 的设置原理 : 任何一个合数都可以分解为比这个合数小的素数之积*/
/* 当ps大于分界线时 n/ps整除的结果 可能有两种情况:
一种是素数(那么它必定小于分界线,所以在之前就被计算过了)
另一种是合数(也小于分界线), 又合数可以分解为比它本身小的素数积,那么他也一定被计算过了*/
for(int idx = 0; ps[idx]*ps[idx] <= n && idx < ps.size(); ++idx) {
if(n % ps[idx] == 0) {
int cnt = 0;
while(n % ps[idx] == 0) {
cnt++;
n /= ps[idx];
}
res *= (1 + cnt * p);
}
}
// printf("\n最后一个素数 %lld\n", n);
/* 相当于cnt等于1的情况,并且此时的n是一个素数 */
if(n > 1)res *= (1 + 1 * p);
return res;
}
int main() {
/*init();*/
ll n;
int T;
for(scanf("%d", &T); T--;) {
scanf("%lld", &n);
// +1 是因为n在2次方中只算了一个约数而结果x<=y 可以取同一个结果2n, 又n^2有两个,更高阶依次类推
printf("%lld\n", (CC(n,2) + 1) / 2);
}
return 0;
}
另外,我们来看一下所有约数和问题
约数的和是在严格分解质因数后,将M的每个质因数最高次幂的所有约数的和相乘所得到的积.
如:21000=2^3×3×5^3×7,所以21000所有约数的和为(1+2+2^2+2^3)×(1+3)×(1+5+5^2+5^3)×(1+7)=74880.
360 = 2^3×3^2×5 约数和为:(1+3+3^2)×(1+2+2^2+2^3)×(1+5) = 1170
- 代码实现如下
#include<bits/stdc++.h>
#define FOR(i,j,n) for(int i=j; i<n; ++i)
#define P pair<int, int>
#define ll long long
using namespace std;
vector<int> ps;
bool is[40010];
void init(){
fill(is, is+40010, 1);
ps.clear();
is[0] = is[1] = false;
FOR(i,2,40010){
if(is[i]){
ps.push_back(i);
for(int j=i+i; j<40010; j+=i) is[i] = false;
}
}
}
vector<P> qin; // 放入因子和次数
ll CC(ll n, ll p=1){
qin.clear();
ll res = 1;
for(int idx=0; ps[idx]*ps[idx]<=n && idx<ps.size(); ++idx){
if(n % ps[idx] == 0){
int cnt = 0;
while(n%ps[idx]==0){
cnt++;
n /= ps[idx];
}
res *= (1 + cnt*p);
qin.push_back(P(ps[idx],cnt));
}
}
if(n > 1) res *= (1 + 1*p);
if(n > 1) qin.push_back(P(n,1));
return res;
}
ll C_sum(ll a){
CC(a);
ll res = 1;
for(int x=0; x<qin.size(); x++){
int cnt = qin[x].second;
int num = qin[x].first;
ll p = 1;
ll now = 1;
FOR(i,1,cnt+1){
p *= num;
now += p;
}
res *= now;
//cout << now << endl;
}
return res;
}
int main(){
init();
int t, a, b;
cout<< C_sum(360) << endl;
cout<< C_sum(21000) << endl;
return 0;
}