课程29_23 1247 邮箱密码
题目:
题目描述:
小婷有一个 E-Mail 邮箱的密码是 n 位长长正整数(n 大于 3),但由于有一段日子不使用此邮箱,她忘记了密码。小婷的生日是 8 月 1 日,她妈妈的生日是 9 月 1 日,她特别喜欢把同时是 81 和 91 的倍数用做密码。此外,小婷还记得这个密码的百位数是 1。请设计一个程序找回这个密码。密码必须是唯一的。
输入描述:
多组输入,占一行,输入一个 n 位数的正整数
输出描述:
占一行,如果满足条件则输出密码,否则输出 wrong。
样例输入:
18923
200000
样例输出:
22113
wrong
解析:
题目里说了,密码同时是81和91的倍数,意思就是说密码是81和91的公倍数。而我们都知道,a和b的所有公倍数,其实就是a和b的最小公倍数的整数倍。而81和91的最小公倍数是7371,也就是说,密码肯定是7371的整数倍。
那我们直接暴力搜索就可以了。题目说密码是唯一的,如果出现了两个满足条件的数字,就说明密码错误,输出wrong。
所以我们准备2个函数:
int f(int n)
{
return n%1000/100;
}
这个函数是用来求百位上是什么数字的。比如f(2501)=5。
int ilen(int n)
{
return log10(n)+1;
}
这个函数是用来求数字的位数的,比如f(1919191919)=10。
注意看完这部分以后别急着走,下面还有一种更简单的方法。
解题:
穷举7371的所有倍数即可。
参考代码:
// TSOJ-1247 邮箱密码
#include <iostream>
#include <cmath>
#include <string>
using namespace std;
int f(int n)
{
return n%1000/100;
}
int ilen(int n)
{
return log10(n)+1;
}
int main()
{
string inp;
int sl,res,temp,iltemp;
while(cin>>inp)
{
sl = inp.length();
res = 0;
for(int i=0;i<291343;i++)
{
temp = i*7371;
iltemp = ilen(temp);
if(iltemp>sl)
break;
if(iltemp==sl){
if(f(temp)==1){
if(res==0)
res = i*7371;
else{
res = -1;
break;
}
}
}
}
if(res!=0 && res!=-1){
cout<<res<<endl;
}else{
cout<<"wrong"<<endl;
}
}
}
比较厉害的解法
在测试代码的过程中,我们会发现,如果我们输入的位数比较大,输出的基本上都是wrong。这个也比较好理解,毕竟位数越多,在这个位数范围里的7371的整数倍自然就多,那么出现多个符合条件(百位是1)的概率自然也大。
那我们是否可以证明这一点呢?
当然可以!
首先,22113是7371的整数,同时它的百位是1。
然后我们构造出两个数字:14742000(7371的2000倍)、22113000(7371的3000倍)。
我们发现这两个数字的百位都是0。很明显,如果一个数字的百位是0,另一个数字的百位是1,这两个数字的和的百位也一定是1。
既然如此,那就意味着有两个8位数(同时也是7371的整数倍)的百位都是1。题目里说了,密码是唯一的,那说明8位数里没有密码。
再往下想,我们会发现:14742000和22113000还可以乘10,变成147420000和221130000,他们的百位仍然是0!那说明9位数里还是没有密码(因为不唯一)。
这个结论可以无限的类推下去,也就是说:8位以及更高的情况,都是wrong。
接下来,我们枚举1~7位的情况:
位数 | 结果 |
---|---|
1 | wrong |
2 | wrong |
3 | wrong |
4 | wrong |
5 | 22113 |
6 | wrong |
7 | wrong |
所以答案就呼之欲出了:
当输入位数为5的时候,输出22113,其他情况输出wrong。
那么超简单代码如下:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string inp;
while(cin>>inp)
{
if(inp.length() == 5)
cout<<"22113"<<endl;
else
cout<<"wrong"<<endl;
}
return 0;
}