所有因数之和 (题目来源:编程爱好者论坛)
2010-11-03 23:09
323 查看
第一题:
时间限制:1s
输入2个数字n,s。求数字n的所有因数之和除以s的余数。
比如输入6 5
6的因数有1,2,3,6,因数之和为12,因为12除以5的余数为2
于是输出2。
假设n,s都不超过5000000
分析:
公式:N可分解为a^m*b^n*c^p……
那末N的所有正因数和为
(1+a+a^2+……+a^m)*(1+b+b^2+……+b^n)*(1+c+c^2+……+c^p)……
简略证明如下:由乘法法则可知,上述括号的连乘积为从所有括号中各取一个相乘,这样就可以保证它包含所有因数
稍微举个简单的例子更好理解:216=2^3*3^3 那末216的所有正因数和即为
(1+2+4+8)*(1+3+9+27)
详细分析下为什么这里要size >=sqrt(5000000)
如果不筛选到sqrt(50000000),那么一旦给出5000000内的大于已经筛选出的素数的幂次。这样就会把这个数当作一个素数,但是事实不是,而是一个比较大的素数的幂次。故至少要筛选到sqrt(5000000)。
参考代码:size=sqrt(5000000)
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#define size 2300
int y[size],p[size],tt;
int prime()//筛选素数
{
int i,j,k=0;
for(i=2;i*i<size;i++)
{
if(!y[i]){for(j=i*i;j<size;j+=i)y[j]=1;}
}
for(i=2;i<size;i++)
{if(!y[i]){p[k++]=i;}}
return k;
}
int SumFactorMod(int n, int s)
{
int sum=1,k=0,ps=0,tm;
while(k<tt&&p[k]<=n)
{
tm=0;
while(n!=0&&!(n%p[k]))
{
n/=p[k];
ps++;
}
for(int i=0;i<=ps;i++)
{
tm+=(int)pow(p[k],i);}
sum*=tm;
sum=sum%s;
k++;ps=0;
}
if(n>1){
sum=(sum*(1+n))%s;
}
return sum;
}
int main()
{
int n,s,sum;
tt=prime();
while(scanf("%d%d",&n,&s)!=EOF)
{
sum=1;
if(n!=1)
sum=SumFactorMod(n,s);
printf("%d/n",sum%s);
}
return 0;
}
第二题:
输入3个数字n, m, s。求数字n的m次方的所有因数之和除以m的余数。
比如输入6 2 5
6^2=36
36的因数有1,2,3,4,6,9,12,18,36,因数之和为91
91除以5的余数为1,所以输出1。
假设n, m, s都不超过5000000
这里规定这个s一直是9901 这样好做点。POJ 1845
这个题目比上面的稍微复杂点。知道了a=p1^m1*p2^m2……
那么给出了a^b=p1^(m1*b)*p2^(m2*b)……指数都乘以了b就行
那么a^b的所有因数和=(1+p1^1+p1^2+……p1^(m1*b))*(1+p2^2+……p2^(m2*b))*……
一样吧。只是这个数一大项数很多,而且乘的也很多,只要解决加快项数的运算就行了。
还有就是p2^(m2*b)可能超出int 也超出__int64或long long 不要怕 这里有个取余嘛
一边算一边取余就是了。
二分法in乘方
如何计算a^n ?
1)计算a*a*a*…*a*a*a,需要计算n-1次乘法,时间复杂度O(n)
2)考虑实例a^4,计算b=a*a,再算c=b*b,则c=a^4,但是只用了两次乘法,效率提高。比如a^9=a*(a^4)*(a^4),只需用4次乘法,一般的,a^n时间复杂度为O(logn)
用于快速算出乘数。
项数也可以用同样方法,二分怎么二分呢?是不是一下子看不出来??
式子都是等比数列吧,项数有奇项与偶项,分开考虑就行了。
首先,偶项:
1+p 1+p+p^2+p^3 1+p+p^2+p^3+p^4+p^5 ……
这些都是偶项的。而且都是后者是前者的两倍,二分的模型来了。
X1=1+p
X2=1+p+p^2(1+p)=(1+p)(1+p^2) X3=1+p+p^2+p^3+p^4+p^5+p^6+p^7=1+p+p^2(1+p)+p^4+p^5+p^6+p^7=(1+p)*(1+p^2)+p^4(1+p)*(1+p^2)=
(1+p)*(1+p^2)*(1+p^4)
所以是:X3=(X2*(1+P^(2^3/2))=(X1*(1+p^(2^2/2))*(1+p^(2^3/2)) 也就是((1+exp(p,k/2))*t)
exp(p,k/2)其实就是算出P^(2^3/2) 这样的。
现在,奇项:
X1 =1 项数 1
X2=1+p+p^2 =X1+p^(3/2)*(1+p*X1) 项数 1*2+1
X3=1+p+p^2+p^3+p^4+p^5+p^6=1+p+p^2+p^3*(1+p*(1+p+p^2))=X2+p^(7/2)*(1+p*X2) 项数 :(1*2+1)*2+1 前面的 蓝色字体的7就是项数 这个对应式子:(t+exp(p,k/2)*(1+p*t))
exp(p,k/2):相当于p^(7/2)
t:就相当于X
相当清楚了吧。。。。。。
完整参考代码://参考哦,不保证没有BUG ~~
/*7100>=sqrt(50000000)*/
#include<stdio.h>
#define size 7100
#define m 9901
int y[size],p[size],k;
void prime()
{
int i,j;
k=0;
for(i=2;i*i<size;i++)
{
if(!y[i]){
for(j=i*i;j<size;j+=i)y[j]=1;
}
}
for(i=2;i<size;i++)
if(!y[i])
p[k++]=i;
}
__int64 exp(__int64 a,__int64 b)
{
if(b==1)
return a;
__int64 t =exp(a,b/2);
if(b&1)
{
return (t*t*a)%m;
}
return (t*t)%m;
}
__int64 sum(__int64 p,__int64 k)
{
if(k==1)
return 1;
__int64 t=sum(p,k/2);
if(k&1)
{
return (t+exp(p,k/2)*(1+p*t))%m;
}
else
return ((1+exp(p,k/2))*t)%m;
}
int main()
{
int a,b,t,cc;
__int64 s;
prime();
cc=k;
while(scanf("%d%d",&a,&b)!=EOF)
{
if(a==1||b==0)
{ printf("1/n");
continue;
}
k=t=0;
s=1;
while(k<cc&&p[k]<=a)
{
t=0;
while(a%p[k]==0)
{
a/=p[k];
t++;
}
s=(s*sum(p[k],t*b+1))%m;
k++;
}
if(a>1)
{
s*=sum(a,b+1);
s=s%m;
}
printf("%d/n",s );
}
return 0;
}
//在 雨中飞燕 那里做了下题目 又有所收获,视乎在统计
a=p1^m1*p2^m2...... 里的m1的时候可以优化。可以想起判断是否是素数只要看小于sqrt(n)
题目是这样的:
#include<stdio.h>
#include<string.h>
#include<math.h>
#define size 32000
int y[size]={0},p[size]={0};
int prime()
{
int i,j,k=0;
for(i=2;i*i<size;i++)
{
if(!y[i])
{
for(j=i*i;j<size;j+=i)
y[j]=1;
}
}
for(i=2;i<size;i++)
if(!y[i])
p[k++]=i;
return k;
}
void yinzi(int n,int k)
{
int i,t,flag=0;
float x=sqrt(n);
for(i=0;i<k&&n>1&&p[i]<=x;i++)
{
t=0;
while(n!=0&&n%p[i]==0)
{
n/=p[i];
t++;
}
if(t)
{
if(flag)
{
printf(" * ");
}
printf("%d",p[i]);
if(t>1)
{
printf("^%d",t);
}
x=sqrt(n);
flag=1;
}
}
if(n>1)
{
if(flag)
printf(" * %d",n);
else
{
printf("%d",n);
}
}
printf("/n");
}
int main()
{
int n;
int k = prime();
while(scanf("%d",&n)!=EOF)
{
printf("%d = ",n);
if(n==1)
{
printf("1/n");
continue;
}
yinzi(n,k);
}
return 0;
}
输入n(1 <= n <= 1e9),有多组测试数据:
616
27
输出:
616 = 2^3 * 7 * 11
27 = 3^3
(注意输出空格,但行末不要有空格)
难度:for beginner
参考代码:
时间限制:1s
输入2个数字n,s。求数字n的所有因数之和除以s的余数。
比如输入6 5
6的因数有1,2,3,6,因数之和为12,因为12除以5的余数为2
于是输出2。
假设n,s都不超过5000000
分析:
公式:N可分解为a^m*b^n*c^p……
那末N的所有正因数和为
(1+a+a^2+……+a^m)*(1+b+b^2+……+b^n)*(1+c+c^2+……+c^p)……
简略证明如下:由乘法法则可知,上述括号的连乘积为从所有括号中各取一个相乘,这样就可以保证它包含所有因数
稍微举个简单的例子更好理解:216=2^3*3^3 那末216的所有正因数和即为
(1+2+4+8)*(1+3+9+27)
详细分析下为什么这里要size >=sqrt(5000000)
如果不筛选到sqrt(50000000),那么一旦给出5000000内的大于已经筛选出的素数的幂次。这样就会把这个数当作一个素数,但是事实不是,而是一个比较大的素数的幂次。故至少要筛选到sqrt(5000000)。
参考代码:size=sqrt(5000000)
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#define size 2300
int y[size],p[size],tt;
int prime()//筛选素数
{
int i,j,k=0;
for(i=2;i*i<size;i++)
{
if(!y[i]){for(j=i*i;j<size;j+=i)y[j]=1;}
}
for(i=2;i<size;i++)
{if(!y[i]){p[k++]=i;}}
return k;
}
int SumFactorMod(int n, int s)
{
int sum=1,k=0,ps=0,tm;
while(k<tt&&p[k]<=n)
{
tm=0;
while(n!=0&&!(n%p[k]))
{
n/=p[k];
ps++;
}
for(int i=0;i<=ps;i++)
{
tm+=(int)pow(p[k],i);}
sum*=tm;
sum=sum%s;
k++;ps=0;
}
if(n>1){
sum=(sum*(1+n))%s;
}
return sum;
}
int main()
{
int n,s,sum;
tt=prime();
while(scanf("%d%d",&n,&s)!=EOF)
{
sum=1;
if(n!=1)
sum=SumFactorMod(n,s);
printf("%d/n",sum%s);
}
return 0;
}
#include<stdio.h> #include<math.h> #include<stdlib.h> #define size 2300 int y[size],p[size],tt; int prime()//筛选素数 { int i,j,k=0; for(i=2;i*i<size;i++) { if(!y[i]){for(j=i*i;j<size;j+=i)y[j]=1;} } for(i=2;i<size;i++) {if(!y[i]){p[k++]=i;}} return k; } int SumFactorMod(int n, int s) { int sum=1,k=0,ps=0,tm; while(k<tt&&p[k]<=n) { tm=0; while(n!=0&&!(n%p[k])) { n/=p[k]; ps++; } for(int i=0;i<=ps;i++) { tm+=(int)pow(p[k],i);} sum*=tm; sum=sum%s; k++;ps=0; } if(n>1){ sum=(sum*(1+n))%s; } return sum; } int main() { int n,s,sum; tt=prime(); while(scanf("%d%d",&n,&s)!=EOF) { sum=1; if(n!=1) sum=SumFactorMod(n,s); printf("%d/n",sum%s); } return 0; }
第二题:
输入3个数字n, m, s。求数字n的m次方的所有因数之和除以m的余数。
比如输入6 2 5
6^2=36
36的因数有1,2,3,4,6,9,12,18,36,因数之和为91
91除以5的余数为1,所以输出1。
假设n, m, s都不超过5000000
这里规定这个s一直是9901 这样好做点。POJ 1845
这个题目比上面的稍微复杂点。知道了a=p1^m1*p2^m2……
那么给出了a^b=p1^(m1*b)*p2^(m2*b)……指数都乘以了b就行
那么a^b的所有因数和=(1+p1^1+p1^2+……p1^(m1*b))*(1+p2^2+……p2^(m2*b))*……
一样吧。只是这个数一大项数很多,而且乘的也很多,只要解决加快项数的运算就行了。
还有就是p2^(m2*b)可能超出int 也超出__int64或long long 不要怕 这里有个取余嘛
一边算一边取余就是了。
二分法in乘方
如何计算a^n ?
1)计算a*a*a*…*a*a*a,需要计算n-1次乘法,时间复杂度O(n)
2)考虑实例a^4,计算b=a*a,再算c=b*b,则c=a^4,但是只用了两次乘法,效率提高。比如a^9=a*(a^4)*(a^4),只需用4次乘法,一般的,a^n时间复杂度为O(logn)
用于快速算出乘数。
项数也可以用同样方法,二分怎么二分呢?是不是一下子看不出来??
式子都是等比数列吧,项数有奇项与偶项,分开考虑就行了。
首先,偶项:
1+p 1+p+p^2+p^3 1+p+p^2+p^3+p^4+p^5 ……
这些都是偶项的。而且都是后者是前者的两倍,二分的模型来了。
X1=1+p
X2=1+p+p^2(1+p)=(1+p)(1+p^2) X3=1+p+p^2+p^3+p^4+p^5+p^6+p^7=1+p+p^2(1+p)+p^4+p^5+p^6+p^7=(1+p)*(1+p^2)+p^4(1+p)*(1+p^2)=
(1+p)*(1+p^2)*(1+p^4)
所以是:X3=(X2*(1+P^(2^3/2))=(X1*(1+p^(2^2/2))*(1+p^(2^3/2)) 也就是((1+exp(p,k/2))*t)
exp(p,k/2)其实就是算出P^(2^3/2) 这样的。
现在,奇项:
X1 =1 项数 1
X2=1+p+p^2 =X1+p^(3/2)*(1+p*X1) 项数 1*2+1
X3=1+p+p^2+p^3+p^4+p^5+p^6=1+p+p^2+p^3*(1+p*(1+p+p^2))=X2+p^(7/2)*(1+p*X2) 项数 :(1*2+1)*2+1 前面的 蓝色字体的7就是项数 这个对应式子:(t+exp(p,k/2)*(1+p*t))
exp(p,k/2):相当于p^(7/2)
t:就相当于X
相当清楚了吧。。。。。。
完整参考代码://参考哦,不保证没有BUG ~~
/*7100>=sqrt(50000000)*/
#include<stdio.h>
#define size 7100
#define m 9901
int y[size],p[size],k;
void prime()
{
int i,j;
k=0;
for(i=2;i*i<size;i++)
{
if(!y[i]){
for(j=i*i;j<size;j+=i)y[j]=1;
}
}
for(i=2;i<size;i++)
if(!y[i])
p[k++]=i;
}
__int64 exp(__int64 a,__int64 b)
{
if(b==1)
return a;
__int64 t =exp(a,b/2);
if(b&1)
{
return (t*t*a)%m;
}
return (t*t)%m;
}
__int64 sum(__int64 p,__int64 k)
{
if(k==1)
return 1;
__int64 t=sum(p,k/2);
if(k&1)
{
return (t+exp(p,k/2)*(1+p*t))%m;
}
else
return ((1+exp(p,k/2))*t)%m;
}
int main()
{
int a,b,t,cc;
__int64 s;
prime();
cc=k;
while(scanf("%d%d",&a,&b)!=EOF)
{
if(a==1||b==0)
{ printf("1/n");
continue;
}
k=t=0;
s=1;
while(k<cc&&p[k]<=a)
{
t=0;
while(a%p[k]==0)
{
a/=p[k];
t++;
}
s=(s*sum(p[k],t*b+1))%m;
k++;
}
if(a>1)
{
s*=sum(a,b+1);
s=s%m;
}
printf("%d/n",s );
}
return 0;
}
/*7100>=sqrt(50000000)*/ #include<stdio.h> #define size 7100 #define m 9901 int y[size],p[size],k; void prime() { int i,j; k=0; for(i=2;i*i<size;i++) { if(!y[i]){ for(j=i*i;j<size;j+=i)y[j]=1; } } for(i=2;i<size;i++) if(!y[i]) p[k++]=i; } __int64 exp(__int64 a,__int64 b) { if(b==1) return a; __int64 t =exp(a,b/2); if(b&1) { return (t*t*a)%m; } return (t*t)%m; } __int64 sum(__int64 p,__int64 k) { if(k==1) return 1; __int64 t=sum(p,k/2); if(k&1) { return (t+exp(p,k/2)*(1+p*t))%m; } else return ((1+exp(p,k/2))*t)%m; } int main() { int a,b,t,cc; __int64 s; prime(); cc=k; while(scanf("%d%d",&a,&b)!=EOF) { if(a==1||b==0) { printf("1/n"); continue; } k=t=0; s=1; while(k<cc&&p[k]<=a) { t=0; while(a%p[k]==0) { a/=p[k]; t++; } s=(s*sum(p[k],t*b+1))%m; k++; } if(a>1) { s*=sum(a,b+1); s=s%m; } printf("%d/n",s ); } return 0; }
//在 雨中飞燕 那里做了下题目 又有所收获,视乎在统计
a=p1^m1*p2^m2...... 里的m1的时候可以优化。可以想起判断是否是素数只要看小于sqrt(n)
题目是这样的:
#include<stdio.h>
#include<string.h>
#include<math.h>
#define size 32000
int y[size]={0},p[size]={0};
int prime()
{
int i,j,k=0;
for(i=2;i*i<size;i++)
{
if(!y[i])
{
for(j=i*i;j<size;j+=i)
y[j]=1;
}
}
for(i=2;i<size;i++)
if(!y[i])
p[k++]=i;
return k;
}
void yinzi(int n,int k)
{
int i,t,flag=0;
float x=sqrt(n);
for(i=0;i<k&&n>1&&p[i]<=x;i++)
{
t=0;
while(n!=0&&n%p[i]==0)
{
n/=p[i];
t++;
}
if(t)
{
if(flag)
{
printf(" * ");
}
printf("%d",p[i]);
if(t>1)
{
printf("^%d",t);
}
x=sqrt(n);
flag=1;
}
}
if(n>1)
{
if(flag)
printf(" * %d",n);
else
{
printf("%d",n);
}
}
printf("/n");
}
int main()
{
int n;
int k = prime();
while(scanf("%d",&n)!=EOF)
{
printf("%d = ",n);
if(n==1)
{
printf("1/n");
continue;
}
yinzi(n,k);
}
return 0;
}
输入n(1 <= n <= 1e9),有多组测试数据:
616
27
输出:
616 = 2^3 * 7 * 11
27 = 3^3
(注意输出空格,但行末不要有空格)
难度:for beginner
参考代码:
相关文章推荐
- 所有因数之和 (题目来源:编程爱好者论坛)
- 编程爱好者论坛第六次编程比赛题目
- 题目:一个数如果恰好等于它的因子之和,这个数就称为"完数"。例如6=1+2+3。编程找出1000以内的所有完数。
- cojs.tk(所有题目来源) 树状数组专练
- 五十道编程小题目 --- 03打印出所有的"水仙花数"java
- 【编程题目】一串首尾相连的珠子(m 个),有 N 种颜色(N<=10),取出其中一段,要求包含所有 N 中颜色,并使长度最短。
- 题目:一个数如果恰好等于它的因子之和,这个数就称为 "完数 "。例如6=1+2+3.编程 找出1000以内的所有完数。(java)
- 【编程题目】在二元树中找出和为某一值的所有路径(树)
- 题目:一个数如果恰好等于它的因子之和,这个数就称为"完数"。例如6=1+2+3.编程 找出1000以内的所有完 数。
- 题目:一个数如果恰好等于它的因子之和,这个数就称为"完数"。例如6=1+2+3。编程找出1000以内的所有完数。
- 50道编程小题目之【分解质因数】
- C89和C99标准比较 【编程爱好者论坛】
- 题目:一个数如果恰好等于它的因子之和,这个数就称为"完数"。 例如6=1+2+3.编程 找出1000以内的所有完数。
- Java笔试常见编程题目:判断101-200 之间有多少个素数,并输出所有素数
- 题目:一个数如果恰好等于它的因子之和,这个数就称为 "完数 "。例如6=1+2+3.编程 找出1000以内的所有完数。
- C100-19 题目:一个数如果恰好等于它的因子之和,这个数就称为“完数”。例如6=1+2+3.编程找出1000以内的所有完数。
- 【程序9】 题目:一个数如果恰好等于它的因子之和,这个数就称为"完数"。 例如6=1+2+3.编程找出1000以内的所有完数。
- 题目:判断101-200之间有多少个素数,并输出所有素数。
- Shell(Bash)编程实例之获取某个文件夹下的所有文件名(含文件夹)
- 百度之星编程题目:C++和Java程序变量名转换器- 程序代码(原创)