ACM必做50题的解题数论文档格式.docx
《ACM必做50题的解题数论文档格式.docx》由会员分享,可在线阅读,更多相关《ACM必做50题的解题数论文档格式.docx(24页珍藏版)》请在冰豆网上搜索。
+b*(x'
-a/b*y'
)
=a*x+b*y
则:
x=y'
y=x'
以上内容转自
由这个可以得出扩展的欧几里德算法:
intexGcd(inta,intb,int&
x,int&
y)
if(b==0)
x=1;
y=0;
intr=exGcd(b,a%b,x,y);
intt=x;
x=y;
y=t-a/b*y;
returnr;
代码:
#include<
iostream>
cstdlib>
cstring>
cmath>
usingnamespacestd;
__int64mm,nn,xx,yy,l;
__int64c,d,x,y;
__int64modd(__int64a,__int64b)
if(a>
=0)
returna%b;
else
returna%b+b;
__int64exGcd(__int64a,__int64b)
if(b==0)
{
x=1;
y=0;
}
__int64r=exGcd(b,a%b);
__int64t=x;
x=y;
y=t-a/b*y;
intmain()
scanf("
%I64d%I64d%I64d%I64d%I64d"
&
xx,&
yy,&
mm,&
nn,&
l);
if(mm>
nn)//分情况
d=exGcd(mm-nn,l);
c=yy-xx;
}
d=exGcd(nn-mm,l);
c=xx-yy;
if(c%d!
printf("
Impossible\n"
);
return0;
l=l/d;
x=modd(x*c/d,l);
///取模函数要注意
%I64d\n"
x);
system("
pause"
}
POJ1142SmithNumber
题意:
寻找最接近而且大于给定的数字的SmithNumber
什么是SmithNumber?
用sum(int)表示一个int的各位的和,那一个数i如果是SmithNumber,则sum(i)=sigma(sum(Pj)),Pj表示i的第j个质因数。
例如4937775=3*5*5*65837,4+9+3+7+7+7+5=42,3+5+5+(6+5+8+3+7)=42,所以4937775是SmithNumber。
思路:
要寻找大于给定数字且最接近给定数字的SmithNumber,只要将给定数字不断的加1,判断它是否是SmithNumber就行了,如果是SmithNumber就立即输出。
但是如何判断是否是SmithNumber呢?
首先就是要对数字进行质因数分解。
质因数分解要保证因子都是质数。
这里先介绍一个如何判断一个数int是否是质数呢,如果对于这个数,i=2.....sqrt(int)都不是它的约数,那int就是一个质数。
所以我们可以将i初始化为2,然后不断递增i,看i是否是int的一个约数,如果是的话那i就是int的一个质因数(因为这个数是从2开始第一个可以整除int的数,它不可能是一个可以分解的合数,否则,它的约数在它之前就整除int),然后将int除以该质因数,重置i为2,重新对int判断它是否是质数。
这样最后剩下的int一定是一个质数,从而对int进行了质因数分解
然后就很简单的将数字各质因数的各位加起来,看和是否等于该数字的各位和,如果相等那它可能就是SmithNumber,为什么说只是可能呢,因为这个数可能是质数,但是质数不是SmithNumber。
#include<
stdio.h>
math.h>
intSum(intnumber)
intsum=0;
while(number!
=0)
sum+=number%10;
number/=10;
returnsum;
boolSmithNumber(intnumber)
inti=2;
inttemp=number;
intsumOfNumber=Sum(number);
while(i<
=(int)sqrt((double)number))
if(number%i==0)
sum+=Sum(i);
number/=i;
i=2;
++i;
//以上的代码做了无谓的计算,可用下面的代码,更新于20090904
//while(number%i==0)
//{
//sum+=sum(i);
//number/=i;
//}
//++i;
sum+=Sum(number);
if(sum==sumOfNumber&
&
number!
=temp)
returntrue;
else
returnfalse;
while(true)
intnum;
%d"
num);
if(num==0)
break;
while(true)
if(SmithNumber(++num))
%d\n"
num);
return0;
ACM——POJ2262(Goldbach'
sConjecture)
题目地址:
题目思路:
对于任何一个偶数n,从x=1和y=n-1开始,看x、y是否是质数,不是则x+=2,y+=2
这题需要开很大的内存,我REn次,居然是因为数组开太小了,我这题耗时不是很理想,但我的耗内存
在我看到的中是最小的,所以看来OJ上的题只要能开内存的就尽量开。
估计我这题用栈耗时了。
stack>
memory.h>
string.h>
//判断是否为质数的函数
intIsPrime(intx)
{
inti;
if(x<
2)
for(i=2;
i<
=(int)(sqrt((double)x+0.5));
i++)
if(x%i==0)
return1;
intmain()
//输入数,输入数/2向上延伸,输入数/2向下延伸,输入数/2
intm_Input,m_Num_Max,m_Num_Min,m_InputToTwo;
//总体输出
charm_Output[1000000];
memset(m_Output,0,1000000);
//标识m_Output的Pos
intm_Output_Pos=0;
//是否找到标识
boolb_Find;
//栈
stack<
int>
m_Stack;
//临时数
intm_Value_Top;
//循环输入
while(scanf("
&
m_Input)&
(m_Input!
=0))
{
b_Find=true;
//m_Input肯定是一个偶数
m_InputToTwo=m_Input/2;
//置值
m_Num_Max=m_Input-1;
m_Num_Min=1;
//寻找,直至都为素数或者找不到为止
while((!
IsPrime(m_Num_Max))||(!
IsPrime(m_Num_Min)))
//否则,前进&
后退2格
m_Num_Max-=2;
m_Num_Min+=2;
//如果发生如下情况,则输出"
Goldbach'
sconjectureiswrong."
if((m_Num_Max<
m_InputToTwo)||(m_Num_Min>
m_InputToTwo))
char*m_TempChar="
sconjectureiswrong.\n"
;
strcat(m_Output,m_TempChar);
b_Find=false;
m_Output_Pos+=strlen(m_TempChar);
//如果找到了
if(b_Find)
//将m_Input转换为字符串存入m_Output
while(m_Input!
=0)
m_Value_Top=m_Input%10;
m_Stack.push(m_Value_Top);
m_Input/=10;
while(!
m_Stack.empty())
m_Value_Top=m_Stack.top();
m_Output[m_Output_Pos++]=m_Value_Top+48;
m_Stack.pop();
//加入=
m_Output[m_Output_Pos++]='
'
='
//将m_Num_Min转换为字符串存入m_Output
while(m_Num_Min!
m_Value_Top=m_Num_Min%10;
m_Num_Min/=10;
//加入+
+'
//将m_Num_Max转换为字符串存入m_Output
while(m_Num_Max!
m_Value_Top=m_Num_Max%10;
m_Num_Max/=10;
//加入\n
\n'
//输出
printf("
%s"
m_Output);
system("
);
POJ2407Relatives
这题从题意可以看出就是求比从1~n-1从有几个数和n没有公共因子,通常的算法很简单就能够想到,我开始也是按通常的做法写了一个,觉得
可能会TLE,果不其然,后来上网查了一下,知道了欧拉函数,这个就是求比n小的数中与n互质(也就是没有公共因子)的算法,看来还是那些经典的算法效率比较高,比纯用暴力试探高多了...
欧拉函数描述如下:
利用欧拉函数和它本身不同质因数的关系,用筛法计算出某个范围内所有数的欧拉函数值。
欧拉函数和它本身不同质因数的关系:
欧拉函数ψ(N)=N{∏p|N}(1-1/p)。
(P是数N的质因数)
如:
ψ(10)=10×
(1-1/2)×
(1-1/5)=4;
ψ(30)=30×
(1-1/3)×
(1-1/5)=8;
ψ(49)=49×
(1-1/7)=42。
注意的是P是N的质因子,这里求质因子还是不能够用常规的判断这个数是不是质数,这样的话可能还会TLE,网上学到他们用的一个while()循环,感觉还挺巧的,学习了...
intenlerFun(intn)
intcount=n;
inti=2;
for(;
i<
=n;
i++)
if(n%i==0)
count-=count/i;
while(n%i==0)
n/=i;
returncount;
intinputVal=0;
intcount=0;
while(scanf("
inputVal)&
inputVal!
=0)
count=enlerFun(inputVal);
count);
POJ1811PrimeTest
MillerRobin素性测试+Pollardrho寻找素因子
MillerRobin和Pollardrho的理论想非常强,细节这里就不说了,可以参考
算法导论第31章
ctime>
#defineMAX_L64//最长位数
#defineTIMES8//millerrobin素性测试的测试次数
#defineMAX_VAL(pow(2.0,60))//定义最大值
#defineCVAL200
//最小的素因子
__int64minFactor;
//
(1)计算a*bmodn,思路:
利用b的二进制表示进行拆分计算
//
(2)例如:
b=1011101那么a*bmodn=(a*1000000modn+a*10000modn+a*1000modn+a*100modn+a*1modn)modn
//(3)思路就是上面描述的那样,那么可以用从低位往高位遍历b,并用a来记录当前位为1的值,每次遇到b当前位为
//1就将结果值加上a并modn,然后a要乘以2
__int64multAndMod(__int64a,__int64b,__int64n)
a=a%n;
__int64res=0;
while(b)
//当前位为1
if(b&
1)
//加上当前权位值
res+=a;
//相当于modn
if(res>
=n)res-=n;
//乘以2,提高一位
a=a<
<
1;
//modn
=n)a-=n;
b=b>
>
1;
returnres;
//
(1)计算a^bmodn,思路:
和上面类似,也是利用b的二进制表示进行拆分计算
b=1011101那么a^bmodn=[(a^1000000modn)*(a^10000modn)*(a^1000modn)*(a^100modn)*(a^1modn)]modn
//1就将结果乘上a并modn,然后a要乘以a以提升一位
__int64modAndExp(__int64a,__int64b,__int64n)
__int64res=1;
while(b>
=1)
//遇到当前位为1,则让res*当前a并modn
res=multAndMod(res,a,n);
//a*a以提升一位
a=multAndMod(a,a,n);
//MillerRobin素性测试,true:
素数,flase:
合数
boolmillerRobin(__int64a,__int64n)
__int64u=0,cur=n-1;
intt=0;
boolfind1=false;
while(cur!
if(!
find1)
intpb=cur%2;
if(pb==0)t++;
elsefind1=true;
if(find1)
cur=cur/2;
u=cur;
cur=modAndExp(a,u,n);
__int64now;
for(intp=1;
p<
=t;
p++)
now=modAndExp(cur,2,n);
if(cur!
=1&
now==1&
cur!
=n-1)
//printf("
%d%d\n"
cur,now);
cur=now;
a:
%I64du:
%I64dn:
%I64dval:
a,u,n,start);
//利用MillerRobin对n进行n次素性测试
booltestPrime(inttimes,__int64n)
if(n==2)returntrue;
if(n%2==0)returnfalse;
__int64a;
intt;
srand(time(NULL));
for(t=1;
t<
=times;
t++)
a=rand()%(n-1)+1;
millerRobin(a,n))returnfalse;
__int64gcd(__int64a,__int64b)
if(b==0)return(a);
returngcd(b,a%b);
__int64PollardRho(__int64n,intc)