整除学习笔记
1.1整除
1.定义
设\(a\)是非零整数,如果存在一个整数\(q\)使得\(b=a\times q\),那么就说\(b\)被\(a\)整除,记做\(a|b\),称\(b\)是\(a\)的倍数,\(a\)是\(b\)的约数
整除具有一些性质
-
如果\(a|b\)且\(b|c\)那么\(a|c\).令\(b=k_1\times a,c=k_2\times b\),那么有\(c=k_1\times k2\times a\),即\(a|c\)
-
\(a|b且a|c\iff a|(b\times x+c\times y),(x,y\in Z)\)
-
若\(m\neq 0\),那么\(a|b\iff (m\times a)|(m\times b)\)
-
设整数\(x,y\)满足\(a\times x+b\times y=1\),且\(a|n,b|n\),那么\((a\times b)|n\)
证明:
\(\because a|n, b|n\)
根据性质3得:\((a\times b)|(b\times n)\)且\((a\times b)|(a\times n)\)
又由性质2得:\((a\times b)|(a\times n\times x+b\times n\times y)\)
其中\(a\times n\times x+b\times n\times y=n\times(ax+by)=n\times 1=n\)
\(\therefore (a\times b)|n\)
-
如果\(b=q\times d+c\),那么\(d|b\)的必要条件为\(d|c\)
2.例题
1.1-1教堂
题意描述
ROMA城中有一些古典的印度式建筑,这些建筑和周围的欧洲建筑风格格格不入。这些伪装成教堂的建筑其实是某国特工的基地。Tomas接受了一项任务,就是从某个教堂出发,逐个访问这些教堂,搞清楚每一个教堂的内部结构,并回到出发的地方。这些教堂很有规律地构成了一个\(m\times n\)的矩形,每个教堂和它的八个方向的教堂有直接的路径相连。水平或垂直方向相邻的教堂之间的路程均为\(1\)。请问Tomas至少需要走多远的路,才能完成这个危险而艰巨的任务呢?
输入
输入一行两个整数m和n\((m,n\leq 10000)\)
输出
输出一行一个实数,表示最少需要走的路程,保留两位小数。
分析
用一些小数据可以得知答案与\(n,m\)的奇偶性有关
#include <bits/stdc++.h>
using namespace std;
int n, m;
int main()
{
cin >> n >> m;
if(n == 1 || m == 1)
printf("%.2lf", (double)(m + n - 2) * 2);
else
{
if(m * n % 2 == 1)
printf("%.2lf", (double)(n * m - 1 + 1.414));
else
printf("%.2lf", (double)(n * m));
}
return 0;
}
imes k-n\times c=gcd()
1.1-2密码
题面
分析
首先,一个二元一次不定方程的一般形式为\(ax+by=c\).其中\(a,b,c\in Z并且a\times b\neq0\).这个方程有整数解的前提条件为\(gcd(a,b)|c\)
设\(x_0,y_0\)为该方程的一组整数解,那么该方程的所有整数解可以表示为
\( \begin{cases} x=x_0+\frac{b}{gcd(a,b)}\times t\\ y=y_0+\frac{a}{gcd(a,b)}\times t \end{cases} \)
设\(x\)为密码,观察这个式子:\(x\times k-n\times c=gcd(x,n)\)
可以得到:这个方程对于\(k,c\)是一定有正整数解的
所以:一定存在一个\(k\)使得\(x\times k\%=gcd(x,n)\)
由题意,\(x\)是密码,那么\((x+x)\%n=2x\%n\)也是密码,类似的\(3x\%n\)也是密码......
综上所述\(x\times k\%n=gcd(x,n)\),\(x\times k\%n\)也是密码
结论1:如果\(x\)是密码,\(gcd(x,n)\)为密码
设\(x,y\)为两个密码,易得\((px+qy)\%n\)也是密码
\(ax+by=gcd(x,y)\)一定有解,所以
$ax+by\equiv gcd(x,y)\pmod n $一定有解
\(\because ax+by\equiv ax+by+pnx+qny \pmod n\)
\(\therefore (a+pn)x+(b+qn)y\equiv ax+by\pmod n,(p,q\in Z)\)
\(\therefore (a+pn)x+(b+qn)y\equiv gcd(x,y)\pmod n\)一定有解,并且\((a+pn),(b+qn)\geq 0\)
\(\because ((a+pn)x+(b+qn)y)\%n\)是密码
\(\therefore gcd(x,y)\)是密码
结论2:如果\(x,y\)是密码,那么\(gcd(x,y)\)为密码
对于任意的一个密码集合\(A\),分析
-
设\(A\)中所有数的\(gcd=x\)
-
由结论2得\(x\in A\)
-
如果密码集合中有比\(x\)小的数\(y\),则\(gcd(x,y) < x\),矛盾,所以\(x\)是\(A\)中最小的数
所以\(A\)中所有的数为\(x,2x,3x,4x......\)
约束条件如下:
-
\(A\)中数尽量多,\(x\)尽量小
-
由结论1得,集合中有两个书\(a_k,gcd(n,a_k)\),所以\(x|gcd(n,a_k)\)
-
对于\(\forall{1\leq i<k}\),\(x|a_i\)不能成立
实现
设\(a_k=gcd(n,a_k)\),在\(O(\sqrt{n})\)时间内处理出\(a_k\)所有的因子,存在\(q\)数组中,接着去除所有为\(gcd(a_i,a_k)\)的因数,除去后的最小因子为\(x\),答案为\(n/x\)
Code
#include <bits/stdc++.h>
#define LL long long
using namespace std;
LL n, k, a[550005], q[550005], f[550005], cnt, ans;
int main()
{
ios::sync_with_stdio(false);
cin >> n >> k;
for (int i = 1; i <= k; i++)
cin >> a[i];
a[k] = __gcd(a[k], n);
for (int i = 1; i < k; i++)
a[i] = __gcd(a[i], a[k]);
for (LL i = 1; i * i <= a[k]; i++)
{
if (a[k] % i == 0)
{
q[++cnt] = i;
if(i * i != a[k]) q[++cnt] = a[k] / i;
}
}
sort(q + 1, q + 1 + cnt);
for(int i = 1; i < k; i ++)
f[lower_bound(q + 1, q + cnt + 1, a[i]) - q] = 1;
for(int i = 1; i <= cnt; i ++)
if(f[i])
for(int j = 1; j < i; j ++)
if(q[i] % q[j] == 0)
f[j] = 1;
for(ans = 1; f[ans]; ans ++);
cout << n / q[ans];
return 0;
}