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
请注意,数字123456789是一个 9 位数字,正好由 1 到 9 之间的数字组成,没有重复。加倍它将得到246913578,它恰好是另一个 9 位数字,正好由 1 到 9 的数字组成,只是排列不同。检查结果,如果我们再次加倍! 现在,您应该检查此属性是否有更多数字。也就是说,将给定的数字加倍,将k位数字加倍,您将判断结果数字是否仅由原始数字中的数字排列组成。
输入规范:每个输入包含一个测试用例。每个案例包含一个不超过 20 位的正整数。
输出规范:对于每个测试用例,如果将输入数字加倍得到的数字仅由原始数字中的数字排列组成,则首先打印一行“是”,如果不是,则打印“否”。然后在下一行中,打印双倍的数字。
思考:
爆int怎么办?可以直接用字符串计算吗?
不行,字符串不能直接计算
Long long 够长,20位可以覆盖
可以使用排序来对应一一数字是否相同,如果不同就说明不是.
虽然不能直接计算很大的数字,但是数字的每一位我们还是能够计算的。
可以从低位慢慢计算到高位.
题目有说是由原始数字排列而成,因此计数是最好的办法。
数据大了的核心就在于手写计算方法
解题过程
先是采用了直接计算,果不其然大的数据会爆int
#include<iostream>
#include<string>
#include<map>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
//小数据适用解法.
int main()
{
long long n, m;
cin >> n;
m =(long long) 2 * n;
string a = to_string(n);
string b = to_string(m);
sort(a.begin(), a.end());
sort(b.begin(), b.end());
for (int i = 0; i < a.size(); i++)
{
if (a[i] != b[i])
{
cout << "No" << endl;
cout << m;
return 0;
}
}
cout << "Yes" << endl;
cout << m;
return 0;
}
//果然没这么简单,对于长数字的处理是不能够直接运算的,long long一样爆
//还是只能用字符串,不能投机取巧了
//一旦数字大了,就不能使用编译器的加减乘除了,必须自己用字符串手写计算方法
AC
#include<iostream>
#include<string>
#include<map>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
int main()
{
string N;
int a[10] = { 0 };
int b[10] = { 0 };
int doub[30] = { 0 };
cin >> N;
bool flag = true;
int j = 0;//表示加倍后的字符长度
for (int i = N.size()-1; i>=0; i--)//必须要倒序,因为必须是从个位开始进位!
{
int t = N[i] - '0';
a[t]++;
int n = doub[j] + t * 2;
if (n < 10)
doub[j] = n;//每次都是细节问题,j又写成i!!!
else
{
doub[j] = n % 10;
doub[j+1] = n / 10;
//为了防止溢出和方便输出,只能单独开一个变量
}
//其实直接看if,else就可以知道为什么最后一个数有不同了
//最后一个数n<10时,j下标是没有下一位的,刚好足够所以
//最后一次j++就刚好为加倍后数字的长度
//而如果n>=10,就多了一个j+1,所以j还要多加一次。
j++;
if (i == 0 && n >= 10)
{
j +=1;//如果最后进位了就加1
}
//就从第一次循坏开始分析,
//j一开始当作下标使用,每一轮循环都会j++
//第一次循环后j就是1,也就是当前确定的字符长度,
//个位是已经被确定了
//所以一直到最后,因为i循环的长度是N的长度,
//每一次循环后j都代表着当前的长度
//那最后j就能完全输出完N的长度,也就是至少已经到达了N的长度
//而如果第一位进位,那就是N长度之外的,循环已经结束,
//因为j已经到达了N的长度。所以要自己额外加1。
//但是这么做很复杂,为了提高可读性。我们索性就直接把j当作下标的移动来使用
//我们自己再开一个变量表示加倍后数字的长度。无非就两种情况,
//要么与N同长,要么就是多出一位自己再加一就行了
//这样,我就不用考虑j是否是加倍数字的长度,随便它怎么变都行
//还是不设变量了。因为本质上不是为了求长度,而是标记目前数据的位置
//为了后序输出,j同时是作为长度又是确定下标位置,不能够单单理解成数字长度
//因此j的设计还是最优的表达。
//最后的j表示加倍后的字符长度,j-1就表示最后一个数字的下标(因为从0开始记录)
}
//j能不能换个更简洁的表达?
//不好换,因为后面很多情况都要牵扯到j
//doub数组也要使用,下标不对齐比较的时候就会很乱很复杂
//之所以不使用i就是因为i并不能代表着加倍后数字的长度,一旦
//加倍后多了一位那就会越界
//而如果往前移动一位,那下标0就会空出,又与N数组无法对齐了
for (int i = 0; i < j; i++)
b[doub[i]]++;
//for (int i = 0; i < j; i++)
for (int i = 0; i < 10; i++)//不是j的长度而是只有0-9的数字比对!
{
if (a[i] != b[i])
{
flag = false;
break;
}
}
if (flag)
cout << "Yes" << endl;
else
cout << "No" << endl;
for (int i =j-1; i>=0; i--)
{
cout << doub[i];
}
return 0;
}
补充解析
#include <iostream>
#include <string>
using namespace std;
int main()
{
string N;
cin >> N;
int doub[21] = { 0 };
int len = N.length();
int j = 0;
int a[10] = { 0 }, b[10] = { 0 };
int flag = 0;
for (int i = len - 1; i >= 0; i--)//计算doub
{
int t = N[i] - '0';//-'0'将字符型转化为整型
a[t]++;//N每位数的个数
int n = doub[j] + t * 2;
//实现单个数字的加倍
//每次都是当前数+新数
if (n < 10)
doub[j] = n;
else
{
doub[j] = n % 10;//进位
doub[j + 1] = n / 10;
//因为每次都是最新的一个数位
//所以直接赋值为整除结果即可,然后下一轮再与下一位数字相加
}
j++;
//前面不管什么情况,自然j都要前往下一位,但最后一位就不同了。
//如果最后一位不需要进位,那么每一次的自增j就会自动加1,也就恰好等于数字的个数了
//而如果下一位进位了,数位增加了,就需要自己再自增j
if (i == 0 && n >= 10)
j++;//第一位需进1的情况
//j实际上指的是数字的个数,因为我们使用下标时,是从0开始的,所以最后要多加一次j
}
for (int i = 0; i < j; i++)
{
b[doub[i]]++;//doub每位数的个数
}
//原理跟哈希相同,只不过巧妙利用了单个数字只可能在1-10之间
//如果范围大了就会浪费空间,用哈希才是最通用的.
for (int i = 0; i < 10; i++)
{
if (a[i] == b[i]) continue;
else
{
flag = 1; break;
}
}
if (flag == 0) cout << "Yes";
else cout << "No";
cout << endl;
for (int i = j - 1; i >= 0; i--)
cout << doub[i];
return 0;
}
后面是尝试不使用计数的方法,而是排序的方法,但是失败了,就作为笔记参考吧
//排序算法困难
#include<iostream>
#include<string>
#include<map>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
int main()
{
//如果使用排序的方法,那么就不能直接使用string,因为数组空间不确定
// 要统一空间,所以要设置长度大小。
//如果要做到最大化优化就需要设置很多条件,
// 因为不确定加倍后的字符长度。
//而且比对字符串时需要到哪里才算停止。
// 还有就是初始化数组有0排序会遇到的问题
//所以索性判断的时候就遍历完数组。
//循环几十次时间也小,没有必要少一点点次数而写一堆代码
//因为插入字符串只会设置足够大小的空间,所以要自己再创建一个设置好空间大小的string 来实现
//排序完后,输出又是个问题,从哪里开始输出,然后又要开一个数组储存原始数据,太麻烦还是记录次数的好
//放弃了。
//之所以会出现这么多问题就是因为我们是将数字当作字符串输出的,
// 既然如此就必须要确定从哪里开始输出
//不能输出多也不能少,而且顺序不能够改变!
//所以最简单还是记录出现次数,排序太繁琐了。
//数组必须是排满比对才好用排序,如果是有多余空间的,
// 就一定不能改变顺序,而且必须要自己建立下标记录
//数据的位置确保数据的正确输出!
string N;
int doub[25] = { 0 };
// cin >> N;
//N.resize(25);//必须先插入后设置大小,不然插入会直接覆盖你原先改的大小。err
//这么写不行,后面的空间全部都是/0而不是0,所以不能直接这么写。
cin >> N;
string newN;
newN.resize(25);
for (int i = 0; i < N.size(); i++)
newN[i] = N[i];
bool flag = true;
int j = 0;//表示加倍后的字符长度
for (int i = N.size() - 1; i >= 0; i--)//必须要倒序,因为必须是从个位开始进位!
{
int t = newN[i] - '0';
int n = doub[j] + t * 2;
if (n < 10)
doub[j] = n;//每次都是细节问题,j又写成i!!!
else
{
doub[j] = n % 10;
doub[j + 1] = n / 10;
//为了防止溢出和方便输出,只能单独开一个变量
}
j++;
if (i == 0 && n >= 10)
{
j += 1;//如果最后进位了就加1
}
}
sort(newN.begin(), newN.end());//字符用begin
sort(doub, doub + 25);//整型用直接+
//for (int i = 0; i < j; i++)
for (int i = 0; i < 25; i++)//不是j的长度而是只有0-9的数字比对!
{
if (N[i] != doub[i] - '0')//记得转换整型为字符
{
flag = false;
break;
}
}
if (flag)
cout << "Yes" << endl;
else
cout << "No" << endl;
for (int i = j - 1; i >= 0; i--)
{
cout << doub[i];
}
return 0;
}