1023. Have Fun with Numbers (20)
时间限制
400 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue
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 file 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
破解过程:
一开始,想要用next_permutation,其实是想要看投机取巧可不可以通过。
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>
#include <cstring>
#include <cmath>
#include <set>
#include <queue>
#include <algorithm>
using namespace std;
long long input,output;
int main(){
cin>>input;
output=2*input;
string str_in=to_string(input);
string str_out = to_string(output);
int flag=0;
// int length=str_in.length();
do{
if(str_out == str_in){
flag=1;
}
}while(next_permutation(str_in.begin(),str_in.end()));
if(flag){
cout<<"Yes"<<endl;
}else{
cout<<"No"<<endl;
}
cout<<output<<endl;
return 0;
}
结果:
有3个测试点运行超时,那么为什么超时,想想都肯定知道一定是循环的时候出的问题。
其实之前还有其他的思路,不只是这一题,每次做题的时候总是会有很多的种思路,多个思路反而会干扰自己,怎么办?尽量多刷题吧;
第二种想法,就是用建一个散列表,题目已经明显说了1~9的数字,那么可以选择用数组【】或者map,这里我觉得数组应该很方便。试着编一下。
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>
#include <cstring>
#include <cmath>
#include <set>
#include <queue>
#include <algorithm>
using namespace std;
long long input,output;
int main(){
cin>>input;
output=2*input;
string str_in=to_string(input);
string str_out = to_string(output);
int arr_in[10]={
0},arr_out[10]={
0};
for(auto x:str_in){
arr_in[x-'0']++;
}
for(auto x:str_out){
arr_out[x-'0']++;
}
int flag=1;
for(int i=1;i<10;i++){
if(arr_in[i]!=arr_out[i]){
flag=0;
}
}
if(flag){
cout<<"Yes"<<endl;
}else{
cout<<"No"<<endl;
}
cout<<output<<endl;
return 0;
}
还是有错误,说明第一种想法逻辑正确,第二种想法的逻辑可能就编写错误了。自己再检查检查。
排除不可能有的错误,数据长度,由于第一种时候就是long long,可以正常通过,所以不想把时间浪费在思考这个对不对上。
于是,我重新阅读题意,修改一个小地方,遍历比较两个散列记录数组的时候,我把原来的从1开始改为了从0开始,因为之前一直关注例程,要注意inPUT给出的数据要求是输入一个正数。
改了之后的程序:
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>
#include <cstring>
#include <cmath>
#include <set>
#include <queue>
#include <algorithm>
using namespace std;
long long input,output;
int main(){
cin>>input;
output=2*input;
string str_in=to_string(input);
string str_out = to_string(output);
int arr_in[10]={
0},arr_out[10]={
0};
for(auto x:str_in){
arr_in[x-'0']++;
}
for(auto x:str_out){
arr_out[x-'0']++;
}
int flag=1;
for(int i=0;i<10;i++){
if(arr_in[i]!=arr_out[i]){
flag=0;
}
}
if(flag){
cout<<"Yes"<<endl;
}else{
cout<<"No"<<endl;
}
cout<<output<<endl;
return 0;
}
可以看到对了一个点,又可以得到两分。那么下面的三个点,为什么显示答案错误呢?看这种排列,总感觉错误会是在同一个关键的地方。
前面自己说了感觉long long没有问题,那么long long最大可以是多少呢?可以存放10进制的20位数吗?long long 是64位,也就是2的64次方,应该拿他与10的20次方进行比较。
2的63次方-1:
可以看到换算成10进制的时候是19位,不满足题目要求的20位,怎么办呢?看来是处理大数问题。祭出晴神宝典。
重点总结一下,数据长度决定数据类型的采用:
整型int类型:占32位。最大值为2的31次方-1。绝对值在10进制的9次方,就是9位数以内的整数可以定义为int类型;
长整型long long:一个整数占64位,最大值为2的63次方-1。也就是说,如果题目要求的整数取值范围超过2147483647,例如10的10次方或者10的18次方,就是一个10进制数位数为10个以上或者18个以上,就得用long long来存储。但是如果是20位数及其以上的话,那么long long类型也不能存储,需要使用大数据类型。
对于浮点型,只需要记住一点,不要使用float,碰到浮点数的数据都应该使用double来存储。
回归这道题,结合《算法笔记》,以及数据长度,可以得出应该是自己在数据长度上面出了问题,看来需要以string类型接收输入数据,自己定义其乘法运算。
其他地方也大多是采用大数据运算的方式解决这道题,刚才我又想到了一种思路,既然是20位,那么对半分为before高10位数,和last10位,那么就肯定可以在long long进行计算了,只需要注意每个要比较还有就是后10位数的最高位可能产生非0进位,这个进位要加在before数才是真正的高位数据。暂时先写到这里,还没有做完,到数学时间了,以后再说.
以上算法思想编写的程序如下:
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>
#include <cstring>
#include <cmath>
#include <set>
#include <queue>
#include <algorithm>
using namespace std;
string str_in,str_out,str_before,str_last;
int main(){
cin>>str_in;
int len_in=str_in.length();
str_before = str_in.substr(0,len_in/2);
int len_before =str_before.length();
str_last = str_in.substr(len_in/2,len_in-len_before);
int num_before=stoll(str_before);
int num_last = stoll(str_last);
int jin=0;
num_before*=2;
num_last*=2;
str_last=to_string(num_last);
if( str_last.length() != len_in-len_before ){
jin=1;
str_last=str_last.substr(1);
}
num_before+=jin;
str_before=to_string(num_before);
int arr_in[10]={
0},arr_out[10]={
0};
for(auto x:str_in){
arr_in[x-'0']++;
}
for(auto x:str_before){
arr_out[x-'0']++;
}
for(auto x:str_last){
arr_out[x-'0']++;
}
int flag=1;
for(int i=0;i<10;i++){
if(arr_in[i]!=arr_out[i]){
flag=0;
}
}
if(flag){
cout<<"Yes"<<endl;
}else{
cout<<"No"<<endl;
}
cout<<str_before<<str_last<<endl;
return 0;
}
但是结果还是有错误。
结果如图,失去耐心,以后遇到这种图,尽量不要浪费时间去想其他的了,直接搞大数据四则运算模板。
这个时候就背模板吧,PAT考场上总共3小时,没有功夫浪费在自己不确定的新奇解题方法上:
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>
#include <cstring>
#include <cmath>
#include <set>
#include <queue>
#include <algorithm>
using namespace std;
struct bign{
int d[21];
int len;
bign(){
memset(d,0,sizeof(d));
len = 0;
}
};
bign change(char str[]){
bign a;
a.len = strlen(str);
for(int i=0;i<a.len;i++){
a.d[i] = str[a.len - i - 1] - '0';
}
return a;
}
bign multi(bign a,int b){
//高精度乘法
bign c;
int carry =0; //进位
for(int i=0;i<a.len;i++){
int temp = a.d[i]*b + carry;
c.d[c.len++] = temp%10; //个位作为该位结果
carry = temp/10; //高位部分作为新的进位
}
while(carry!=0){
//和加法不一样,乘法的进位可能不止1位,因此用while
c.d[c.len++] = carry%10;
carry /=10;
}
return c;
}
bool Judge(bign a,bign b){
//判断b的所有位是否是a的某个排列
if(a.len != b.len ){
return false;
}
int count[10] = {
0};
for(int i=0;i<a.len;i++){
count[a.d[i]]++; //数位a.d[i]对应的count值加1
count[b.d[i]]--;
}
for(int i=0;i<10;i++){
if(count[i]!=0){
return false;
}
}
return true;
}
void print(bign a){
for(int i=a.len-1;i>=0;i--){
printf("%d",a.d[i]);
}
}
int main(){
char str[21];
gets(str); //输入数据
bign a = change(str); //转换为bign
bign mul = multi(a,2); //计算a*2
if(Judge(a,mul) == true){
printf("Yes\n");
}else{
printf("No\n");
}
print(mul);
return 0;
}