大一寒假集训2020.1.4
GCD&&LCM
取模运算的运算规则
(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
最大公约数 一般使用欧几里得算法;即辗转相除法。
最小公倍数的求法是在最大公约数基础上得来。
lcm(x,y)=x*y/gcd(x,y)
辗转相除求最大公约数
#include <bits/stdc++.h>
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 main()
{
int a, b;
while (cin >> a >> b)
{
int gy, gb;
gy = gcd(a, b);
gb = a / gy * b;
cout << gy << " " << gb << endl;
}
return 0;
}
已知一个数,和最大公约数求另一个数。
暴力写法,循环遍历
#include <bits/stdc++.h>
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 main()
{
int a, r;
while (cin >> a >> r)
{
for (int i = 1; 1; i++)
{
if (gcd(a, i) == r && i != r) //找到退出。
{
cout << i << endl;
break;
}
}
}
return 0;
}
在单个基础上,多次使用GCD
#include<bits/stdc++.h>
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 dgcd(long long a[],long long n)
{
int b=a[0];
for(int i=1;i<n;i++)
{
b=gcd(b,a[i]);
}
return b;
}
int main()
{
long long n;
long long a[100];
long long gy;
while(cin>>n)
{
for(int i=0;i<n;i++)
{
cin>>a[i];
}
gy=dgcd(a,n);
cout<<gy<<endl;
}
return 0;
}
与上同理,多个数使用LCM
#include<bits/stdc++.h>
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 gb;
gb=a/gcd(a,b)*b;
return gb;
}
int dlcm(long long a[],long long n)
{
int gb=a[0];
for(int i=1;i<n;i++)
{
gb=lcm(a[i],gb);
}
return gb;
}
int main()
{
long long a[100];
long long n;
while(cin>>n)
{
for(int i=0;i<n;i++)
{
cin>>a[i];
}
long long result;
result=dlcm(a,n);
cout<<result<<endl;
}
return 0;
}
题目不难,难在优化。
直接暴力找就会TLE教做人
所以我们有技巧的暴力
#include <bits/stdc++.h>
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;
}
int main()
{
long long t;
while (scanf("%lld", &t) != EOF)
{
while (t--)
{
long long x, y;
scanf("%lld%lld", &x, &y);
long long ans = 0;
long long h;
h = x * y;
for (int a = x; a <= y; a++) //从x到y
{
if (h % a == 0) //满足两条条件就可知他是一种情况
{
if (h / a <= y && h / a >= x && gcd(a, h / a) == x)
{
ans++;
}
}
}
cout << ans << endl;
}
}
return 0;
}
这是数学题,蒟蒻不会
有手写的证明过程
可以证gcd(x,y)=gcd(a,b)
然后就很简单了。
用完全平方展开
#include <bits/stdc++.h>
using namespace std;
int gcd(int a, int b)
{
if(a<b)
{
swap(a,b);
}
int r;
while (b>0)
{
r = a % b;
a = b;
b = r;
}
return a;
}
int main()
{
int t;
while (scanf("%d",&t)!=EOF)
{
while (t--)
{
int a, b;
int result;
scanf("%d %d",&a,&b);
int y;
y = gcd(a, b);
result = (a * a) - (2 * b * y);
printf("%d\n",result);
}
}
return 0;
}
这个又是个优化题。。。
需要把遍历的数据减少防TLE
#include<bits/stdc++.h>
using namespace std;
long long gcd(long a, long b)
{
long long r;
r = a % b;
while (r)
{
a = b;
b = r;
r = a % b;
}
return b;
}
int main()
{
long long x,y;
cin>>x>>y;
long long gy;
gy=gcd(x,y);
int ans=0;
for(int i=1;i*i<=gy;i++) //i*i<=gy;
{
if(gy%i==0)
{
ans++;
}
}
if(sqrt(gy)==(int)sqrt(gy)) //根号下的比较即可
{
ans=ans*2-1;
}
else
{
ans*=2;
}
cout<<ans<<endl;
return 0;
}
快速幂取模
我们采用分治的思想来解决这种问题
当采用计算机语言时
ab=((a(b/n))n)*a(b%n)
当n=2时
ab=(a(b/2))(a(b/2))*a(b%2)
(ab)%mod=(a(b/2))%mod(a(b/2))%mod*a(b%2)%mod
而后对a^(b/2)进行相同的操作
模板题
#include <bits/stdc++.h>
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 a, b, c;
while (cin >> a >> b >> c)
{
long long h;
h = quickmod(a, b, c);
cout << h << endl;
}
return 0;
}
好的,又是一道数学题,直接用给的公式递归
果断TLE糊你一脸
所以我们根据他给的公式找通项公式。
可得2*3^n;
那我就来了
#include<bits/stdc++.h>
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 n;
long long y;
while(cin>>n)
{
y=(6%1000000007)*(quickmod(3,n-1,1000000007))%1000000007;
cout<<y<<endl;
}
}
虽然写的丑,但是起码是过去了。
学长好坏,出这么个题,本蒟蒻一点思路都没有
据说这题好像只要找出给的数在二进制下有几个1,就是二的几次方
那我就会了
#include <bits/stdc++.h>
using namespace std;
int main()
{
long long n;
int counter = 0;
while (scanf("%lld",&n)!=EOF)
{
counter=0;
for (int i = 0; i <= n; i++)
{
if (i == n - (n ^ i))
{
counter++;
}
}
printf("%d\n",counter);
}
return 0;
}
今天写的不是题,是数学题。主要练习了对程序的优化,让程序快速高效的走大数据,不会TLE