2.取模运算的运算规则
(a + b) % p = (a % p + b % p) % p
(a - b) % p = (a % p - b % p) % p
(a * b) % p = (a % p * b % p) % p
a ^ b % p = ((a % p)^b) % p 【a的b次方】
3.欧几里得算法又叫辗转相除法,用来求得两个数的最大公约数,记作gcd(a,b)
其原理如下:
4.那么,怎么用程序实现欧几里得算法?
实际上我们可以写两种形式的辗转相除:递归和非递归。
非递归的模板: 递归的模板:
5.
请计算2个数的最大公约数和最小公倍数;(最大公约数可以使用辗转相除法,最小公倍数=2个数的乘积/它们的最大公约数;)
Input
输入数据有多组,每组2个正整数a,b(2 Output
在一行内输出a和b的最大公约数和最小公倍数;
Sample Input
15 10
Sample Output
5 3
#include
#include
using namespace std;
/*int gcd(long long int a,long long int b)
{ long long int r;
r=a%b;
while(r)
{ a=b;
b=r;
r=a&b;
}
return b;
}
int lcm(long long int a,long long int b)
{
return a/lcm(a,b)*b;
}*/
long long gcd(long long a,long long b)
{
return b?gcd(b,a%b):a;}
long long lcm(long long a,long long b)
{
return a/gcd(a,b)*b;}
int main()
{
}long long int n,m,k,l;
while(scanf("%lld %lld",&n,&m)!=-1)
{
printf("%lld %lld",gcd(n,m),lcm(n,m));
}
return 0;
}
【小张自己来】
#include
#include
using namespace std;
long long gcd(long long a,long long b)
{
long long r;
r=a%b;
while(r)
{
a=b;
b=r;
r=a&b;
}
return b;
}
long long lcm(long long a,long long b)
{
long long l;
l=a/gcd(a,b)*b;
return l;
}
int main()
{
long long int n,m;
while(scanf("%lld %lld",&n,&m)!=-1)
{
printf("%lld %lld",gcd(n,m),lcm(n,m));
}
return 0;
}
其实强大的C++内置了gcd函数!使用方法:__gcd(a,b)
#include
using namespace std;
int main()
{
long long a,b;
while(cin>>a>>b)
printf("%lld %lld\n",__gcd(a,b),a/__gcd(a,b)*b);
return 0;
}
————————————————
DB最近沉迷于数论,她最近在研究最小公倍数和最大公约数,她的老师Z给她留了一个作业:在[x,y]区间中,求两个整数最大公约数是x且最小公倍数是y的个数。
Input
第一行输入一个T(T<=300),表示有T组数据,接下来输入两个数 x, y(1<=x<=y<=1e6)(含义如题)
Output
输出一行表示答案
Sample Input
1
2 12
Sample Output
4
Hint
(2,12) (4,6) (6,4) (12,2)
#include
#include
using namespace std;
int gcd(int a,int b)
{
int r;
r=a%b;
while(r)
{
a=b;
b=r;
r=a%b;
}
return b;
}
int lcm(int a,int b)
{
int p;
p=a/gcd(a,b)*b;
return p;
}
int main()
{
int x,y,i;
int sum,n,j;
scanf("%d\n",&n);
while(n--)
{
scanf("%d %d",&x,&y);
sum=0;
for(i=x;i<=y;i+=x)
{
if(y%i==0)
{
for(j=x;j<=y;j++)
{
if(y%j==0)
{
if(gcd(i,j)==x&&lcm(i,j)==y)
sum++;
}
}}
}
printf("%d\n",sum);
}
return 0;
}
有三个正整数a,b,c(0 Input
每行输入两个正整数a,b。
Output
输出对应的c,每组测试数据占一行
Sample Input
6 2
12 4
Sample Output
4
8
#include
using namespace std;
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;}
int main()
{
int a,b,i;
while(cin>>a>>b)
{
for(i=b+1;;i++)
{
if(gcd(a,i)==b)
{
printf("%d\n",i);break;}
}
}
return 0;
}
给定n(n<=10)个正整数,你的任务就是求它们的最大公约数,所有数据的范围均在long long内。
Input
输入数据有多组,每组2行,第一行为n,表示要输入数字的个数,接下来第二行有n个正整数。
Output
输出一个数,即这n个数的最大公约数。
Sample Input
5
2 4 6 8 10
2
13 26
Sample Output
2
13
#include
using namespace std;
long long gcd(long long a,long long b)
{
return b?gcd(b,a%b):a;}
int main()
{
long long n,i,a[11];
while(cin>>n)
{
for(i=1;i<=n;i++)
cin>>a[i];
for(i=1;i<=n-1;i++)
a[i+1]=gcd(a[i],a[i+1]);
printf("%lld\n",a[n]);
}
return 0;
}
#include
using namespace std;
long long gcd(long long a,long long b)
{
return b?gcd(b,a%b):a;}
int main()
{
long long n,i,a[11];
while(cin>>n)
{
for(i=1;i<=n;i++)
cin>>a[i];
for(i=1;i<=n-1;i++)
a[i+1]=gcd(a[i],a[i+1]);
printf("%lld\n",a[n]);
}
return 0;
}
给定n(n<=10)个正整数,你的任务就是求它们的最小公倍数,所有数据的范围均在long long内。
Input
输入数据有多组,每组2行,第一行为n,表示要输入数字的个数,接下来第二行有n个正整数。
Output
输出一个数,即这n个数的最小公倍数。
Sample Input
5
2 4 6 8 10
2
13 26
Sample Output
120
26
#include
using namespace std;
long long gcd(long long a,long long b)
{
return b?gcd(b,a%b):a;}
long long lcm(long long a,long long b)
{
return a/gcd(a,b)*b;}
int main()
{
long long n,i,a[11];
while(cin>>n)
{
for(i=1;i<=n;i++)
cin>>a[i];
for(i=1;i<=n-1;i++)
a[i+1]=lcm(a[i],a[i+1]);
printf("%lld\n",a[n]);
}
return 0;
x+y=a,lcm(x,y)=b;已知a和b求解x^2+
y^2
Input
多组数据输入。
第一行一个t表示a,b数对的数量。
接下来t行2个数表示a,b
T<=100000
a,b<10^9;
Output
每组样例输出t行每行一个数表示x2+y2;
Sample Input
2
6 4
6 3
Sample Output
20
18
#include
using namespace std;
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;}
int main()
{
int t,a,b;
ios::sync_with_stdio(false);
while(cin>>t)
{
while(t--)
{
cin>>a>>b;
printf("%d\n",a*a-2*b*gcd(a,b));
}
}
return 0;
}
今天西片同学又被高木同学捉弄了,高木同学跟西片同学玩了这么一个游戏。两人心中分别想一个数字,这两个数字分别为x和y(1<=x,y<=1e18),然后让西片同学说出一共有多少个整数既是x的因子,又是y的因子。由于西片和高木很有默契,所以保证他们两个想的数x和y的最大公因数不会超过1e9。这个问题又难住了西片同学了,你能帮帮西片同学告诉他答案吗?
Input
单组输入
数据占一行,包含两个整数x和y(1<=x,y<=1e18),保证gcd(x,y)<=1e9。
Output
输出既是x因子又是y因子的整数的个数。输出占一行
Sample Input
12 36
Sample Output
6
#include
using namespace std;
typedef long long ll;
ll x,y,ans=1;
int main()
{
ios::sync_with_stdio(false);
cin>>x>>y;
ll k=__gcd(x,y);
for(ll i=2;i*i<=k;i++)
{
ll c=0;
while(k%i==0)
k=k/i,c++;
ans*=(c+1);
}
if(k>1)ans*=2;
printf("%lld\n",ans);
return 0;
}
给定A,B,C,计算AB%C,这里AB代表A的B次方。
Input
输入数据有多组,每组数据一行,有3个正整数分别为A,B和C,1<=A,B,C<=1000000000
Output
输出A^B%C的值
Sample Input
2 3 5
8 2 10
Sample Output
3
4
#include
#include
using namespace std;
long long quickmod(long long a,long long b,long long c)
{
int ret=1;
while(b)
{
if(b&1)
ret=ret*a%c;
a=a*a%c;
b/=2;
}
return ret;
}
int main()
{
long long int x,y,z,q;
while(scanf("%lld %lld %lld",&x,&y,&z)!=-1)
{
q=quickmod(x,y,z);
printf("%d\n",q);
}
return 0;
}
库特很喜欢做各种高深莫测的数学题,一天,她在书上看到了这么一道题。a[1]=6,a[2]=18;a[n]=2a[n-1]+3an-2,对于给出的某个数字n,求a[n]。库特一想这道题太简单了,可是看到n的范围是(n<=1e18),对于这么大范围的数,库特不知道该怎么做了,聪明的你,快来帮帮库特解决这个问题吧。(由于答案可能很大,请将答案对1e9+7(即1000000007)取模)。
Input
一个整数n(1<=n<=1e18)
Output
a[n]对1e9+7取模后的答案
Sample Input
5
Sample Output
486
乍看之下这是一道递推题,但是只要简单推理一下或者你多写几项你就能发现,a[n]=2*pow(3,n),求a[n]对1e9+7取模后的答案,所以这显然是一道快速幂取模的题目。套一下快速幂板子很容易就能得到答案了。
#include
#include
using namespace std;
long long mode=1e9+7;
long long mod(long long a,long long b)
{
int ret=1;
while(b)
{
if(b&1)
ret=ret*a%mode;
a=a*a%mode;
b/=2;
}
return ret;
}
long long int i,n;
int main()
{
while(scanf("%lld",&n)!=-1)
{
i=mod(3,n);
i=i*2;
i=i%mode;
printf("%lld",i);
}
return 0;
}
ljw这几天给大一同学讲课的时候,觉得自己太菜了,于是他做了一道无聊的数学题,
但是他觉得这题太难了,所以他把问题交给了聪明的你,你能帮他解决这个问题吗?
问题如下:
给你一个方程:n−(n^x)−x=0 (其中 ^ 表示两个数异或,并不是表示幂次符号哦)
现在给你n的值,问有多少种x的取值使得方程成立(数据保证n在2的30次方范围内)
Input
多组输入数据。
每组输入数据包含一个整数n,含义如题。
Output
每组输入数据输出一个整数,表示解的个数。
Sample Input
0
2
1073741823
Sample Output
1
2
1073741824
Hint
异或指的是,两个数的每一个二进制位,如果相同,异或结果为0,如果不相同,异或结果为1。
样例解释:
当n=0时,可以证明x只有等于0时才满足方程,
此时x只有1种满足条件的取值,所以输入的n=0时,你需要输出1。
先移项:a=x+(a^x),然后看二进制数的某一位,讨论即可发现规律:
a x+(a^x)
1 0+(1^0)==1
1 1+(1^1)==1
0 0+(0^0)0
0 1+(0^1)10
可以发现,第四种情况(a0,x1)会改变产生进位,改变了a的值,所以排除第四种情况。
综合第三,四种情况,可以发现,如果a的某一位为0的话,那么x对应位只能为0。
再来看第一,第二种情况,我们发现,当a的某一位为1时,x的对应位可以为1,可以为0。
所以,我们只需求出a的二进制数中,有多少个1即可,答案即为2^n
#include
using namespace std;
int pre[35],a,k,sum;
int main(){
pre[0]=1;
for(int i=1;i<=30;i++)
pre[i]=2*pre[i-1];//先打表
while(cin>>a){
for(int i=1;i<=30;i++)
if(pre[i]>a){
k=i-1;break;//求出a用二进制表示时有k位
}
sum=0;
for(int i=0;i<=k;i++){
if((1<<i)&a)
sum++;
}
printf("%d\n",pre[sum]);
}
return 0;
}
移项a=(a⊕x)+x
可以发现x二进制位上为1的地方必定是a二进制位为1的地方。计算出a的二进制中1的个数为b。答案就是2^b。
#include
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const ll mod=1e9+7;
ll ksm(ll a,ll b)
{
ll res=1ll;
while (b)
{
if (b&1)
res*=a;
b>>=1
a=a*a;
}
return res;
}
int chan(int a)
{
int res=0;
while (a)
{
if (a&1)
res++;
a>>=1;
}
return res;
}
int main()
{
//freopen("std.in","r",stdin); //freopen("std.out","w",stdout);
int a;
while (~scanf("%d",&a))
{
ll ans=0;
ans+=ksm(2,chan(a));
printf("%lld\n",ans);
} return 0;
}