假设,进而设 整除乘积 . 证明 必整除 .
证:
又.
假设 ,进而设. 证明乘积.
证:
设 为奇数, , 证明
两两互素,即它们中的每一对都互素。在证明勾股定理(定理 )时需用到这个结论。(提示:假设有一个公素因数, 应用引理:如果一个素数整除某个乘积,则它必整除其中一个因数。)
证:(1)假设 ,不妨设,则, 又 ,得出,这与矛盾。 是奇数。
(2) 假设,不妨设,令,则。根据假设可得 即 矛盾。易证均为奇数时, .
(3) ,证明同(1)
给出下述公式的归纳证明。
(a)
(b)
(c)
(d)
引申:可使用算两次的思想得出一些其他和式的公式。一时兴起算的,发现并不存在某种特定规律,就没往后算了。
本习题要求你继续研究区域。牢记你所做的,本题中假设奇数不存在!
(a) 在区域:无法分解为 数乘积的数。扩充到整数区域便于记忆的定义,所有质因子中的个数仅有一个的偶数。
(b) 本身是素数,得证。假设当时,均可被分解为-素数的乘积,若是-素数,得证,反之可以被分解为数乘积,不妨令,显然,同理,得证。
(c) (1)引入奇数以便于理解的写法,
(2) 是最小的。
(3)
(d) 引入奇数以便于理解的写法,
欢迎进入 世界,这里只有被 除余 的正整数。换句话说,数是
(另一种叙述是形如 的数。)在 世界中,我们不可能把数相加,但可以把数相乘,因为如果 与 都被 除余 ,则它们的乘积也是这样。(你知道为什么成立吗?)如果对某 数 有 ,则称 整数 . 如果 的 因数仅为 与它自身,则称 是 素数。(当然,我们不认为 本身是 素数。)
(a) 质数筛法可得:
(b) 构造:
编写将(正)整数 分解成素数乘积的程序。(如果 ,确保转到出错信息而不是出现死循环)。表示 的因数分解的简便方法是 阶矩阵。因此,如果
则将 的分解存储成矩阵
(如果你的计算机不允许动态存储分配,则必须确定允许存储多个因数的预存量)
(a) 编写程序,通过试除每个可能因数 分解 . (这是一种极其低效的方法,但常用作初学习题)
(b) 修改程序存储前 个(或更多)素数,在找最大素因数前先将 除去这些素数。如果你不管 或 或 倍数的,而只把较大的 作为可能的因数,那么可提高程序运行速度。利用 不能被 与 之间的任何整数整除时 必为素数的事实,也可提高效率。使用你的程序求 与 间所有整数的完全因数分解。
(c) 编写一段子程序以优美格式打印 的因数分解。最令人满意的是指数出现在指数位置;但是,如果这不可能,则将(比如说)的因数分解打印成
(为了便于阅读,不打印等于 的指数)
见代码部分。 的质因数个数至多有 个。
public class PrimeSplit {
private int M;
private List<Integer> ls;
public PrimeSplit(int max) {
M = (int) (Math.sqrt(max) + 1);
boolean[] p = new boolean[M];
ls = new ArrayList<>();
Arrays.fill(p, true);
for (int i = 2; i < M; i++) {
if(p[i]) ls.add(i);
for(int x: ls){
if(x * i >= M) break;
p[x * i] = false;
if(i % x == 0) break;
}
}
}
public List<int[]> split(int n){
List<int[]> res = new ArrayList<>();
for (int x: ls) {
if(x * x > n) break;
int l = 0;
while(n % x == 0){
n /= x;
l++;
}
if(l > 0) res.add(new int[]{x, l});
}
if(n > 1) res.add(new int[]{n, 1});
return res;
}
public static void main(String[] args){
int M = 1_000_030;
PrimeSplit ps = new PrimeSplit(M);
StringBuffer sb = new StringBuffer();
for (int i = 1_000_000; i <= M; i++) {
List<int[]> split = ps.split(i);
sb.append(i);
sb.append('=');
boolean f = false;
for (int[] x: split){
if(f) sb.append('*');
sb.append(x[0]);
if(x[1] > 1){
sb.append('^');
sb.append(x[1]);
}
f = true;
}
System.out.println(sb);
sb.setLength(0);
}
}
} 前面手撕了部分自然数幂级求和公式,没找出明显规律,心想着不应该啊,然后去网上搜了搜,真被我发现了现成的结论,即伯努利数。
制作表格
得到伯努利数。
观察通项公式的系数,将其相加总是得到 ,事实上将 代入即可。因此我们有,消去 提出项,即有。以计算为例
也可以考虑将展开,将替换为伯努利数,也能得到上述公式。伯努利数的性质和应用远不止这一点,而且还有很多没弄明白。伯努利数虽然可以计算出来,但本身没啥规律,或者是规律不够明显?
public BigInteger[][] bernoulli(int n){
//包含分子分母各两项
BigInteger[][] b = new BigInteger[n + 1][2];
b[0] = new BigInteger[]{BigInteger.ONE, BigInteger.ONE};
BigInteger[] f = new BigInteger[n + 2];
Arrays.fill(f, BigInteger.ONE);
for (int i = 1; i <= n; i++) {
for (int j = i; j > 0; j--) {
//C(i, j),也即C(i, i - j)
f[j] = f[j].add(f[j - 1]);
}
b[i] = new BigInteger[]{BigInteger.ZERO, BigInteger.ONE};
//根据已有结论:大于1的奇数项为0.可进行剪枝
if(i > 1 && i % 2 == 1) continue;
for (int j = 0; j < i; j++) {
if(j > 1 && j % 2 == 1) continue;
sub(b[i], b[j], f[j]);
}
gcd(b[i], i + 1);
}
return b;
}
private void gcd(BigInteger[] t, int i) {
//gcd法约分
t[1] = t[1].multiply(BigInteger.valueOf(i));
BigInteger a = t[1], b = t[0].abs();
while(b.compareTo(BigInteger.ZERO) > 0){
BigInteger tp = a.mod(b);
a = b;
b = tp;
}
t[0] = t[0].divide(a);
t[1] = t[1].divide(a);
}
public void sub(BigInteger[] a, BigInteger[] b, BigInteger mul){
//通分
a[0] = a[0].multiply(b[1]).subtract(b[0].multiply(a[1]).multiply(mul));
a[1] = a[1].multiply(b[1]);
} 假设 与 .
(a) ,
,
(b)
假设 和 . 证明 .
,,代入,即得
求下述同余式的所有不同余解。
(a)
(b) 无解
(c)
(d)
(e) 无解
证明下述整除性试验结果.
(a)
(b)
(c)
(d)
(e)
求下述线性同余式的所有不同余解。
(a)
(b) 无解
(c)
确定下述同余式的不同余解的个数。无需求出解。
(a) ,无解
(b) ,有个解
(c) ,无解
编写程序解同余式 . (如果不整除 c, 则输出出错信息和 的值)测试程序,求出习题8.6中同余式的所有解。
见代码部分
编写程序,输入正整数 和 整系数多项式 ,输出同余式 的所有解。(无需细想,只需让 分别取 ,看看哪些值是解。)取多项式
对下述每个 值
通过解同余式 来测试程序。
见代码部分
(a) 同余式
有多少个解?有四个解嘛?还是少于四个解?
(b) 考察同余式 ,当 时它有几个解?注意它的解多余两个。为什么这个结果与模 多项式根定理(定理 8.2)矛盾?
(a) 使用习题8.8的程序验证,得两个解。事实上原式,而 不是 的平方剩余。
(b) 答:四个解。8 不是素数。
设 为不同素数。同余式
最多可能有多少个解?这里我们照样只关心模 不同余的解。
答:4 个。 和 ,最多各两个解,进而两两组合解同余式,最多可得四个解。
public Pair<Boolean, List<Integer>> remainder(int a, int c, int m){
//欧几里得扩展法
int[] g = _gcd(a, m);
List<Integer> ls = new ArrayList<>();
if(c % g[2] != 0){
ls.add(g[2]);
return new Pair<>(false, ls);
}
c = c * g[0] / g[2];
for (int i = 0; i < g[2]; i++) {
ls.add(c);
c = (c + m / g[2]) % m;
}
return new Pair<>(true, ls);
}public List<Integer> remainder(int[] F, int m){
List<Integer> ls = new ArrayList<>();
for (int i = 0; i < m; i++) {
int x = 1;
int M = 0;
for (int f : F) {
M = (M + f * x) % m;
x = x * i % m;
}
if(M == 0) ls.add(i);
}
return ls;
}