1.自守数
一个数的平方的尾数等于这个数的数是自守数
法一
//知识点:若要分离一个数的最后x位,只需要用次数对10^x取余即可,注意这里的最后x位指的是它表示的实际数值,不是仅仅一个数,例如我想求345的最后2位数,我用345 % 100得到的是45,而不是4,想要得到4需要这么做345 % 100 - 345 % (100 / 10), 这就是自守数算法中的重要步骤,当然取4也可以用(345 % 100) / 10得到,这种方法我用在求水仙花数的一类题上
#include<stdio.h>
int main()
{
int mul, number, k, b, c;
printf("1-10000之间共有这些自守数:\n");
for (number = 1; number < 10000; number++)
{ for (mul = number, k = 10; (mul /= 10) > 0; k *= 10);
//k控制着求部分积的次数,k的n次方代表求n次部分积,每次以10倍递减,例如number为25,得出k为100,求两次部分积
c = k;//每次对每次部分积截取后几位,例如c为100(10^2),证明每次截取后两位
mul = 0;//用来累加结果
b = 10;//因为第一次截取乘数肯定截取的是它的最后一位,由知识点可知b初始值为10
while (k > 1)//控制着次数
{
mul = (mul + (number%k)*(number%b - number % (b / 10)) )% c;//难点,也是核心语句
k = k / 10;
b = b * 10;
}
if (mul == number)
{
printf("%d\n", mul);
}
}
return 0;
}
/*思路过程:
1.要求1 - 10000中所有的自守数,肯定少不了对每个数遍历判断的操作(最外层for循环)
2.拿到一个数下一步该怎么做呢,就用到了图片中的算法思想,从中理解出,对于每次求得的部分积,我都要取它的最后"位数"位数,比如number位25,则我每次部分积要取它的最后2位,如何求最后两位呢?请看知识点中的讲解,所以第二步我们就要通过number的位数确定这个"10的乘方数",比如number为5,自然k取10.
3.开始进行while循环中的操作了,对mul = (mul + (number%k)*(number%b - number % (b / 10)) % c; 进行如下讲解:
将这一长串分为两部分看,第一部分(number%k)。第二部分(number%b - number % (b / 10)。再看看图片中的算法思想和知识点中的讲解就恍然大悟了,后面的对c取余,也是算法思想中说的,对各个部分积后三位求和后,再对最终结果后三位求和。
------------------------------------------------------------------------------------------
下面代码是我之前自己写的求自守数的方法,显然跟上面比相差太多了*/
#include<stdio.h>
int main()
{
int a[10], i, j, k = 0, sum, n = 0, m = 0, p, q, s;
for (i = 1; i < 10000; i++)
{
p = 1;//用于将数组尾数变成一个数时用的变量
k = 0;//记录某个数的平方是几位数
j = i * i;
m = 0;
s = i;
q = 0;
sum = 0;
while (s % 10 != 0)//用q保存所求数是几位数
{
q++;
s = s / 10;
}
while (j % 10 != 0)//k保存所求数的平方是几位数,并将其逆序保存在数组中
{
a[k] = j % 10;
k++;
j = j / 10;
}
while (m < q)//算出平方数的最后几位,由于是逆序存储则可以直接计算
{
sum = sum + p * a[m];
p = p * 10;
m++;
}
if (sum == i)
{
printf("%d\n", sum);
}
}
}
2.两个极大数相乘
错误示范
#include<stdio.h>
int main()
{
//char str[100];//存结果
int a, b;
scanf("%d %d", &a, &b);
char *MMax(int, int);
printf("%s\n", MMax(a, b));
return 0;
}
char s[20] = { 0 };
char *MMax(int a, int b)
{
int sum = 0, temp1 = 0, m,k=0;
char *p = s;
int i = 0;
if (a > b)
{
int temp;
temp = a;
a = b;
b = temp;
}
while (b)
{
s[i++] = b % 10+'0';
b /= 10;
}
for (m = 0; m < i; m++)
{
sum = (s[m]-'0') * a + temp1;
s[k++] = (sum % 10)+'0';
temp1 = sum / 10;
}
if (temp1)
{
s[m++] = (temp1%10)+'0';
temp1 /= 10;
}
s[m] = '\0';
return p;
}
/*
妄图返回指向结果数组的字符指针,却殊不知,s数组的生命周期出了MMax函数就结束了,所以此时的p也是没有指向的,所以结果出错
*/
正确
#include<stdio.h>
int main()
{
//char str[100];//存结果
int a, b;
scanf("%d %d", &a, &b);
void MMax(int, int);
MMax(a, b);
return 0;
}
void MMax(int a, int b)
{
int s[20] = { 0 };
int sum = 0, temp1 = 0, m,k=0;
int i = 0;
if (a > b)
{
int temp;
temp = a;
a = b;
b = temp;
}
while (b)//将较大数存进数组中(倒着存的)
{
s[i++] = b % 10;
b /= 10;
}
for (m = 0; m < i; m++)
{
sum = s[m] * a + temp1;//记
s[k++] = sum % 10;
temp1 = sum / 10;
}
while(temp1)
{
s[k++] = temp1%10;
temp1 /= 10;
}
while (k > 0)
{
printf("%d", s[k - 1]);
--k;
}
}
思考:根据大数相乘的原理写出求自守数的方法
#include<stdio.h>
int main()
{
char str[100];//存结果
int a, b;
long int result;
long int MMax(int, int,long int);
for (long int i = 1; i < 10000; i++)
{
result = 0;
if (i == MMax(i, i, result))
printf("自守数:%ld\n", i);
}
return 0;
}
long int MMax(int a, int b,long int result)
{
int s[20] = { 0 };
int sum = 0, temp1 = 0, m, k = 0;
int i = 0;
if (a > b)
{
int temp;
temp = a;
a = b;
b = temp;
}
while (b)//将较大数存进数组中(倒着存的)
{
s[i++] = b % 10;//i存放两个数中大数的位数
b /= 10;
}
for (m = 0; m < i; m++)
{
sum = s[m] * a + temp1;//记
s[k++] = sum % 10;//k存放结果的位数
temp1 = sum / 10;
}
while (temp1)
{
s[k++] = temp1 % 10;
temp1 /= 10;
}
//取出与原数相同位数的数返回
int f, ss = 1;
for ( f = 0; f <i; f++)
{
result = result + s[f]*ss;//语句1
//result = result*10 + s[f];//语句2
ss *= 10;
}
return result;
}
知识点:
1.若一个数组逆序存放你需要的原数,比如原数为123456,在数组中存成了654321,想要正确的返回原数应采用 1语句的方法,需要设置一个变量初始为1
2.若一个数组正序存放你想要的原数,如原数123456,数组中也是123456,只需用语句2即可