Have Fun with Numbers
Notice that the number 123456789 is a 9-digit number consisting exactly the numbers from 1 to 9, with no duplication. Double it we will obtain 246913578, which happens to be another 9-digit number consisting exactly the numbers from 1 to 9, only in a different permutation. Check to see the result if we double it again!
Now you are suppose to check if there are more numbers with this property. That is, double a given number with k digits, you are to tell if the resulting number consists of only a permutation of the digits in the original number.
Input Specification:
Each input contains one test case. Each case contains one positive integer with no more than 20 digits.
Output Specification:
For each test case, first print in a line “Yes” if doubling the input number gives a number that consists of only a permutation of the digits in the original number, or “No” if not. Then in the next line, print the doubled number.
Sample Input:
1234567899
Sample Output:
Yes
2469135798
思路
由题干的信息可以发现,测试例子是不多于20位的数字
且已知long long的上限也仅只能到达19位
由此,笔者尝试使用STL中的vector容器利用字符串实现庞大数字的加减
这是笔者想到的较为简便的解法:
解题
部分实现:
#include <iostream>
#include <vector>
using namespace std;
vector<char> multi(vector<char> &str)
{
vector<char> str0;
int *arr=new int[str.size()];
int len=str.size(),i,j;
for(i=len-1,j=0;i>=0;i--,j++)
arr[j]=(str[i]-'0')*2;
char x;
x=(arr[0]>=10)?(arr[0]-10+'0'):(arr[0]+'0');
str0.push_back(x);
for(i=1;i<len;i++)
{
if(arr[i-1]>=10)
x=((arr[i]>=10)?(arr[i]-10+'0'):(arr[i]+'0'))+1;
else
x=(arr[i]>=10)?(arr[i]-10+'0'):(arr[i]+'0');
str0.push_back(x);
}
if(arr[i-1]>=10) str0.push_back('1');
return str0;
}
bool judge(vector<char> &str1,vector<char> &str2)
{
int result=0;
int len1=str1.size();
int len2=str2.size();
if(len1!=len2) return false;
for(int i=0;i<len1;i++)
result^=(str1[i]^str2[i]);
if(result) return false;
return true;
}
int main()
{
vector<char> num;
while(1)
{
char x;
cin.get(x);
if(x=='\n') break;
num.push_back(x);
}
vector<char> num0=multi(num);
if(judge(num,num0))
cout<<"Yes"<<endl;
else cout<<"No"<<endl;
for(int i=num0.size()-1;i>=0;i--)
cout<<num0[i];
return 0;
}
在五个测试节点中始终有一个无法通过,起初始终不能理解
经过仔细思考,笔者发现
函数:
bool judge(vector<char> &str1,vector<char> &str2)
{
int result=0;
int len1=str1.size();
int len2=str2.size();
if(len1!=len2) return false;
for(int i=0;i<len1;i++)
result^=(str1[i]^str2[i]);
if(result) return false;
return true;
}
是通过位运算异或判断两个vector容器是否完全一致
int类型变量result:
若为0,则返回真
若为1,则返回假
这里有一个较为严重的漏洞,比如测试用例
123456798
输出
Yes
246913596
这里就能明显发现,结果中 6 和 9 重复出现
而导致在异或的过程中, 6 和 9 的异或代替了 7 和 8 的异或
其实在二进制表示中如果没有产生进位,那么运算符 ^ 和 + 是可以等价的
所以凑巧运算结果是一致的
这导致了结果的错误和测试不通过
由于水平有限,笔者为保证程序的正确性只能将原函数进行了相对复杂的改变
将原有的 O(n) 变为了 O(n^2),代码也相应变长了一点
完全实现:
#include <iostream>
#include <vector>
using namespace std;
vector<char> multi(vector<char> &str)
{
vector<char> str0;
int *arr=new int[str.size()];
int len=str.size(),i,j;
for(i=len-1,j=0;i>=0;i--,j++)
arr[j]=(str[i]-'0')*2;
char x;
x=(arr[0]>=10)?(arr[0]-10+'0'):(arr[0]+'0');
str0.push_back(x);
for(i=1;i<len;i++)
{
if(arr[i-1]>=10)
x=((arr[i]>=10)?(arr[i]-10+'0'):(arr[i]+'0'))+1;
else
x=(arr[i]>=10)?(arr[i]-10+'0'):(arr[i]+'0');
str0.push_back(x);
}
if(arr[i-1]>=10) str0.push_back('1');
return str0;
}
bool judge(vector<char> &str1,vector<char> &str2)
{
int count=0;
int len1=str1.size();
int len2=str2.size();
if(len1!=len2) return false;
for(int i=0;i<len1;i++)
{
count=0;
for(int j=0;j<len1;j++)
if(str2[j]!=str1[i]) count++;
if(count==len1) return false;
}
return true;
}
int main()
{
vector<char> num;
while(1)
{
char x;
cin.get(x);
if(x=='\n') break;
num.push_back(x);
}
vector<char> num0=multi(num);
if(judge(num,num0))
cout<<"Yes"<<endl;
else cout<<"No"<<endl;
for(int i=num0.size()-1;i>=0;i--)
cout<<num0[i];
return 0;
}
其中修改函数:
bool judge(vector<char> &str1,vector<char> &str2)
{
int count=0;
int len1=str1.size();
int len2=str2.size();
if(len1!=len2) return false;
for(int i=0;i<len1;i++)
{
count=0;
for(int j=0;j<len1;j++)
if(str2[j]!=str1[i]) count++;
if(count==len1) return false;
}
return true;
}
解决了以后确实长舒一口气,这个问题确实困扰了身为咸鱼的笔者一段时间
希望也能给大家一点帮助吧(手动滑稽)