同余:
重要算法:扩展欧几里得算法;
作用:例如gcd(a,b) = d,求两个系数a*x+b*y = d,扩展欧几里得算法的作用就是能够快速求出x,y.
公式推导:
就是欧几里得公式的原理,每次欧几里得递归之后,x,y都是不一样的,上面我们是通过公式推导找出了这一层和下一层的关系,而最后一层,很显然就是x=1,y=0,然后逆推回去就行。
通过最终的化简可以得到最终的公式为:
x = x0 + k(b/gcd);
y = y0 - k(a/gcd);
解决什么问题:
最主要解决线性同余方程:
有解条件:
矩阵乘法:
1.线性同余方程:
1.同余方程
求关于 x 的同余方程 ax≡1(modb) 的最小正整数解。
输入格式
输入只有一行,包含两个正整数 a,b,用一个空格隔开。
输出格式
输出只有一行,包含一个正整数 x,表示最小正整数解。
输入数据保证一定有解。
数据范围
2≤a,b≤2×1e9
输入样例:
3 10
输出样例:
7
题解:
#include<iostream>
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b,ll& x,ll& y)
{
if(!b)
{
x = 1;
y = 0;
return a;
}
int d = gcd(b,a%b,x,y);
int t = y;
y = x - a/b*y;
x = t;
return d;
}
int main()
{
ll a,b,x,y;
cin>>a>>b;
gcd(a,b,x,y);
cout<<(x%b+b)%b<<endl;
}
2.青蛙的约会
两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面。
它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止。
可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置。
不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去,总能碰到对方的。
但是除非这两只青蛙在同一时间跳到同一点上,不然是永远都不可能碰面的。
为了帮助这两只乐观的青蛙,你被要求写一个程序来判断这两只青蛙是否能够碰面,会在什么时候碰面。
我们把这两只青蛙分别叫做青蛙 A 和青蛙 B,并且规定纬度线上东经 0 度处为原点,由东往西为正方向,单位长度 1 米,这样我们就得到了一条首尾相接的数轴。
设青蛙 A 的出发点坐标是 x,青蛙 B 的出发点坐标是 y。
青蛙 A 一次能跳 m 米,青蛙 B 一次能跳 n 米,两只青蛙跳一次所花费的时间相同。
纬度线总长 L 米。
现在要你求出它们跳了几次以后才会碰面。
输入格式
输入只包括一行 5 个整数 x,y,m,n,L。
输出格式
输出碰面所需要的跳跃次数,如果永远不可能碰面则输出一行 Impossible。
数据范围
x≠y<2000000000,
0<m,n<2000000000,
0<L<2100000000
输入样例:
1 2 3 4 5
输出样例:
4
解法:
代码:
#include<cstring>
#include<iostream>
using namespace std;
typedef long long ll;
ll exgcd(ll a,ll b,ll& x,ll& y)
{
if(!b)
{
x = 1;
y = 0;
return a;
}
ll d = exgcd(b,a%b,x,y);
ll t = y;
y = x - a/b*y;
x = t;
return d;
}
int main()
{
ll a,b,m,n,L;
cin>>a>>b>>m>>n>>L;
ll x,y;
ll d = exgcd(m - n,L,x,y);
if((b - a) % d) cout<<"Impossible"<<endl;
else
{
x = x*(b-a)/d;
ll t = abs(L/d);
cout<<(x%t+t)%t<<endl;
}
}
3.最幸运的数字
8 是中国的幸运数字,如果一个数字的每一位都由 8 构成则该数字被称作是幸运数字。
现在给定一个正整数 L,请问至少多少个 8 连在一起组成的正整数(即最小幸运数字)是 L 的倍数。
输入格式
输入包含多组测试用例。
每组测试用例占一行,包含一个整数 L。
当输入用例 L=0 时,表示输入终止,该用例无需处理。
输出格式
每组测试用例输出结果占一行。
结果为 Case i:+一个整数 N,N 代表满足条件的最小幸运数字的位数。
如果满足条件的幸运数字不存在,则 N=0。
数据范围
1≤L≤2×109
输入样例:
8
11
16
0
输出样例:
Case 1: 1
Case 2: 2
Case 3: 0
解法:
#include <iostream>
using namespace std;
typedef long long LL;
//欧几里得算法
int gcd(LL a, int b) {
return b ? gcd(b, a % b) : a;
}
//试除法求欧拉函数
LL get_euler(LL c) {
LL res = c;
for (int i = 2; i <= c / i; ++ i) {
if (c % i == 0) {
int s = 0;
while (c % i == 0) ++ s, c /= i;
res = res / i * (i - 1);
}
}
if (c > 1) res = res / c * (c - 1);
return res;
}
//龟速乘
LL qmul(LL a, LL b, LL c) {
LL res = 0;
while (b) {
if (b & 1) res = (res + a) % c;
a = (a + a) % c;
b >>= 1;
}
return res;
}
//快速幂
LL qmi(LL a, LL b, LL c) {
LL res = 1;
while (b) {
if (b & 1) res = qmul(res, a, c);
a = qmul(a, a, c);
b >>= 1;
}
return res;
}
int main() {
int T = 1;
LL L;
while (cin >> L, L) {
int d = gcd(L, 8);
LL c = 9 * L / d;
LL phi = get_euler(c);
LL res = 1e18;
if (c % 2 == 0 || c % 5 == 0) res = 0; //判断c和10是否互质(10必须模c余1)
else {
for (LL i = 1; i <= phi / i; ++ i) {
if (phi % i == 0) {
if (qmi(10, i, c) == 1) res = min(res, i);
if (qmi(10, phi / i, c) == 1) res = min(res, phi / i);
}
}
}
printf("Case %d: %lld\n", T ++ , res);
}
return 0;
}
作者:一只野生彩色铅笔
链接:https://www.acwing.com/solution/content/47979/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
矩阵乘法: