1.整除问题 。
http://acm.nefu.edu.cn/JudgeOnline/problem/115.jsp
水题,斐波那契数列是有循环节的。
罗列斐波那契数列前几项如1 1 2 3 5 8 13 21 34 55 89 144 233 ... 发现能被3整除的刚好是4的循环,能被4整除的刚好是6的循环,猜想存在这种关系,可以用数学归纳法证明:
f ( n ) = f ( n - 1 ) + f ( n - 2 )
= 2 * f ( n -1 ) + f ( n - 3 )
= 3 * f ( n - 3 ) + 2 * f ( n - 4 ) // 可以证明被3整除 循环节是4
= 5 * f ( n -4 ) + 3 * f ( n - 5 )
= 8 * f ( n - 5 ) + 5 * f ( n - 6 ) // 可以证明被4整除 循环节是6
题目也求能否被 12 整除 , 而3 和4 的最小公倍数就是 12 所以它的循环节是 4 和 6 的最小公倍数也就是 12 。
#include
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
if(n%12==0)
printf("YES\n");
else
{
if(n%4==0)
printf("3\n");
else if(n%6==0)
printf("4\n");
else
printf("NO\n");
}
}
return 0;
}
杭电上一道类似的题 水啊
http://acm.hdu.edu.cn/showproblem.php?pid=1021
思路是一样的....水啊
#include
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
if(n%4==2)
printf("yes\n");
else
printf("no\n");
}
return 0;
}
2. gcd 和 lcm
a * b = gcd ( a,b ) * lcm ( a,b )
gcd ( ma,mb ) = m * gcd ( a,b ) (那个啥书上的是错的,这个才是对的)
辗转相除法: a = q * b + r gcd ( a,b ) = gcd ( b,r )
http://acm.nefu.edu.cn/JudgeOnline/problem/116.jsp
水题....哦..这个oj蛮坑人的,_int64做的就PE了,只能用long long
#include
long long gcd(int x,int y)
{
if(y==0) return x;
return gcd(y,x%y);
}
int main()
{
int a,b;
while(scanf("%d%d",&a,&b)!=EOF)
{
printf("%lld\n",(long long)a*b/gcd(a,b));
}
return 0;
}
3.扩展欧几里得
设a和b不全为0,则存在整数x和y使得 gcd ( a,b ) = a * x +b * y
推论: a , b 互素 当且仅当 a * x + b * y =1
http://poj.org/problem?id=1061
丫的,第一次做扩展欧几里得,模板妹的坑爹,尤其是这本书的这一块
线性同余,这是一个好东西的嘛
关于这个题,首先还是列方程:(中间可以进行优化,先求gcd(a,b),然后以方程两边除它可以简化)
设青蛙跳了 t 步 他们相遇的充要条件就是 (x+mt)-(y+nt)=pl 即 (n-m)* t + l * p = x-y
可以直接看成 a*x+b*y=gcd(a,b)
关于模板函数中带 &的变量当然是之后要返回那个值,所以最后得到的x,y便是一组通解
数论概论书上讲了个线性方程定理(第三版 p25): g = gcd ( a , b ),方程 ax + by = g 存在一个解(x , y )由函数返回得到,则方程的每一个解都可以表示成 (x+k*b/g,y-k*a/g )(k为任意整数) 那么剩下的问题就好解决了
#include
long long gcd(long long a,long long b)
{
if(b==0) return a;
return gcd(b,a%b);
}
long long exgcd(long long a,long long b,long long &x,long long &y)
{
long long ans,t;
if(b==0)
{
x=1;y=0;return a;
}
else
{
ans=exgcd(b,a%b,x,y);
t=x;x=y;y=t-(a/b)*y;
}
return ans;
}
int main()
{
long long x,y,n,m,l;
long long a,b,d,k,s,t,r;
scanf("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&l);
//方程:(n-m)*s+l*k=d
a=n-m;
b=l; // a*s+b*k=d;
d=x-y;
r=gcd(a,b);
if(d%r!=0)
{
printf("Impossible\n");
return 0;
}
a/=r;
b/=r;
d/=r;
exgcd(a,b,s,k);
s*=d;// 方程的通解:s=s1+t*b/d;k=k1+t*a/d;
//由于求的是最小解,则令s=0;
k*=d; //乘以d后分别是 s1=-t*b 和 k1=-t*a
t=s/b;//通解的系数的相反数嘛
s=s-t*b;
if(s<0)
s+=b;
printf("%lld\n",s);
return 0;
}
#include
#include
typedef long long int64;
using namespace std;
int64 exgcd(int64 m,int64 &x,int64 n,int64 &y)
{
//尼玛坑爹的欧几里得,还是递归的简单
int64 x1,y1,x0,y0;
x0=1;y0=0;
x1=0;y1=1;
int64 r=(m%n+n)%n;
int64 q=(m-r)/n;
x=0;y=1;
while(r)
{
x=x0-q*x1;y=y0-q*y1;x0=x1;y0=y1;
x1=x;y1=y;
m=n;n=r;r=m%n;
q=(m-r)/n;
}
return n;
}
int main()
{
int yy;
int64 r,t,x,y,m,n,l,ar,br,cr;
cin>>x>>y>>m>>n>>l;
int64 M=exgcd(n-m,ar,l,br);
if((x-y)%M||m==n)
cout<<"Impossible"<
http://acm.nefu.edu.cn/JudgeOnline/problem/84.jsp
算是一样的题吧
同样先写出方程 s * d - t * n = m
#include
long long gcd(long long a,long long b)
{
if(b==0) return a;
return gcd(b,a%b);
}
long long exgcd(long long a,long long b,long long &x,long long &y)
{
if(b==1) //貌似是说走一圈的意思
{
x=1;
y=1-a;
}
else
{
long long x1,y1;
exgcd(b,a%b,x1,y1);
x=y1;
y=x1-x*(a/b);
}
}
int main()
{
int tc;
long long n,d,x,y,g,s,t,res;
scanf("%d",&tc);
while(tc--)
{
scanf("%lld%lld%lld%lld",&n,&d,&x,&y);
x=(y-x+n)%n;
g=gcd(d,n);
if(x%g)
{
printf("Impossible\n");
continue;
}
n/=g;
d/=g;
exgcd(d,n,s,t);
if(s<0)
s+=n;
res=(s*x/g)%n;
printf("%lld\n",res);
}
return 0;
}
至于课后习题,简单的就不累述了,难的我也解决不了,时间紧迫,以后再看吧:
设a>b,gcd(a,b)=1,证明 (a^m-b^m,a^n-b^n)=a^(m,n) - b^(m,n) (主要思路估计还是辗转相除变形)