L1-046 整除光棍 (20 分)
这里所谓的“光棍”,并不是指单身汪啦~ 说的是全部由1组成的数字,比如1、11、111、1111等。传说任何一个光棍都能被一个不以5结尾的奇数整除。比如,111111就可以被13整除。 现在,你的程序要读入一个整数x
,这个整数一定是奇数并且不以5结尾。然后,经过计算,输出两个数字:第一个数字s
,表示x
乘以s
是一个光棍,第二个数字n
是这个光棍的位数。这样的解当然不是唯一的,题目要求你输出最小的解。
提示:一个显然的办法是逐渐增加光棍的位数,直到可以整除x
为止。但难点在于,s
可能是个非常大的数 —— 比如,程序输入31,那么就输出3584229390681和15,因为31乘以3584229390681的结果是111111111111111,一共15个1。
输入格式:
输入在一行中给出一个不以5结尾的正奇数x
(<1000)。
输出格式:
在一行中输出相应的最小的s
和n
,其间以1个空格分隔。
输入样例:
31
输出样例:
3584229390681 15
这道题是比较典型的超过正常整数范围的题目,一般在大数处理中很常见,先解决这个问题,这里用到了模拟除法原则,由于被除数未知,但是他有规律可循,所以先找到大于x,且最接近x的光棍数字,比如输入的数字x为9,则第一个光棍数字选择11,然后模拟除法原则,
虽然写的丑,但还是很直观的,接下来看代码就很直观了,
#include<bit/stdc++.h>
using namespace std;
typedef unsigned long long ll;
int main() {
ll N, big = 1, cnt = 1;;
scanf_s("%lld", &N);
while (big < N) {//先找到N附近的光棍
big *= 10;
big += 1;
++cnt;
}
while (1) {//除法公式分解,可以用于大数除法
printf_s("%lld", big / N);
if (big % N == 0) {
break;
}
else {
big %= N;
big *= 10;
big += 1;
++cnt;
}
}
printf_s(" %lld", cnt);
return 0;
}
这是一种解法。不过这道题用万进制的效果不好,
下面看一下万进制用于阶乘的例子,我们知道即使是64位的整数,其最大的整数也只能到18446744073709551615,在高位阶乘的时候远远不够,这时只能用其他方法来保存阶乘后得到的值,废话不多说,直接上代码
#include<iostream>
#include<iomanip>
using namespace std;
int main()
{
void factorial(int n); //阶乘函数
int n;
while (cin >> n)
factorial(n);
return 0;
}
void factorial(int n)
{//万进制
int a[10001];//用于存储数值
int places, carry, i, j;
a[0] = 1;
places = 0; //当前数的总位数
for (i = 1; i <= n; i++)
{
carry = 0; //进位
for (j = 0; j <= places; j++)
{//先从低位(每十进制的四位为万进制的一位)开始计算,由低到高,按照乘法规则相乘,进位
a[j] = a[j] * i + carry;//相乘,加上进位
carry = a[j] / 10000;//求出进位(后面加到高位)
a[j] %= 10000;//留下取余后的数字
}
if (carry > 0) //如果一个数的总前一位大于一万,则向前进位
{
places++;//for循环后的进位是新增加的位
a[places] = carry;
}
}
/*
输出
最高位原样输出,
其他位小于1000的,高位补0
*/
cout << a[places];
for (i = places - 1; i >= 0; i--)//从后面开始输出
cout << setw(4) << setfill('0') << a[i];
cout << endl;
}
用整数数组来保存输出值,每个数组元素的值得范围为0-999,阶乘的时候,每个数组都与下一位要乘的数直接相乘,溢出的值向前面进位,按照这种方式,可以实现任何进制。