1023 Have Fun with Numbers

本文介绍了解决PAT1023问题的方法,该问题要求检查一个给定的20位数加倍后是否形成原数的一个排列。通过使用字符串存储大数并实现大数乘法,结合hashTable来判断排列的有效性。

1023 Have Fun with Numbers (20 point(s))

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 kdigits, 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),将它们加倍后得到的是这个数的另一个排列。本题要求计算输入的2倍,并且判断它是否是输入的另一个排列。

由于至多有20位,不可以用int甚至long long存储。因此用string读入,并将它存储到数组中,然后按照大数加法/乘法的方式处理。对于另一个排列,必然对于每一个数字,有相同的个数。利用Hash思想,只需要用长度为10的int[]来存储数位个数即可。 

关键点:1. 大数加法/乘法;2. hashTable(判断是否是同一个排列)。

注意点:熟悉大数问题(string转数组、数值的高位在字符串数组的低位、进位处理、多余位处理等)

#include<iostream>
#include<string>
using namespace std;
const int N = 21;
int number[N];
int rec[10]={0};
int rec2[10]={0};
int main(void)
{
	string s;
	cin>>s;
	bool flag = true;
	//记录每个数字的个数,并且存入数组
	int len = s.length();
	int dlen;
	for(int i=len-1;i>=0;i--){
		int tmp = s[i]-'0';
		number[len-1-i] = tmp;
		rec[tmp]++;
	} 
	//大数加法
	int carry = 0;
	for(int i=0;i<len;i++){
		int tmp = carry+2*number[i];
		number[i] = tmp % 10;
		carry=tmp/10; 
	} 
	if(carry!=0){
		number[len]=carry;
		dlen = len+1;
		flag = false;
	}
	else dlen = len;
	for(int i=0;i<dlen;i++){
		rec2[number[i]]++;
	}
	for(int i=0;i<=9;i++){
		if(rec[i]!=rec2[i]){
			flag = false;
			break;
		}
	}
	if(!flag) cout<<"No"<<endl;
	else cout<<"Yes"<<endl;
	for(int i=dlen-1;i>=0;i--) cout<<number[i];
	return 0;
}

拓展:

1. <algorithm>定义的count函数和count_if函数,可以用于vector和数组。

链接:https://blog.youkuaiyun.com/lyj2014211626/article/details/69615514

2. PAT1023参考链接:https://blog.youkuaiyun.com/richenyunqi/article/details/79555465

#include<bits/stdc++.h>
using namespace std;
string input,result="";//输入的大整数、2倍后的大整数
int hashTable[10];//辅助数组
void mul(){//大整数乘法
    int num=0;
    for(int i=0;input[i]!='\0';++i){
        int k=2*(input[i]-'0')+num;
        result+=k%10+'0';
        num=k/10;
    }
    if(num!=0)
        result+=num+'0';//如果最终进位不为0,置于result数组末尾
}
int main(){
    cin>>input;
    reverse(input.begin(),input.end());//翻转读取到的数组
    mul();
    for(int i=0;input[i]!='\0';++i){//遍历新数原数两个数组,在相应的hashTable数组下标下进行递增递减
        ++hashTable[input[i]-'0'];
        --hashTable[result[i]-'0'];
    }
    bool yes=(count(hashTable,hashTable+10,0)==10);//遍历整个hashTable数组,看元素0的个数是否为10
    reverse(result.begin(),result.end());//将result数组翻转
    printf("%s\n%s",yes?"Yes":"No",result.c_str());
    return 0;
}

 

### 介绍 倍增算法(Doubling Algorithm)是计算机科学中一种常见的优化策略,广泛应用于数据结构、图论、字符串处理等领域。其核心思想是通过预先存储某些信息,使得在后续查询或操作时可以快速利用这些信息来减少重复计算,从而提高效率。 ### 原理与实现 #### 1. **二进制拆分与预处理** 倍增算法的核心在于将问题的规模按照二进制进行拆分,并通过预处理来加速后续的查询。例如,在求解最近公共祖先(LCA)问题时,倍增法通过为每个节点预存其向上 $2^k$ 层的祖先信息,使得每次查询可以在 $O(\log n)$ 的时间内完成。 以下是一个 LCA 中倍增算法的简单实现示例: ```python import sys sys.setrecursionlimit(1000000) def dfs(u, p): depth[u] = depth[p] + 1 parent[u][0] = p for k in range(1, LOG): parent[u][k] = parent[parent[u][k-1]][k-1] for v in graph[u]: if v != p: dfs(v, u) def lca(u, v): if depth[u] < depth[v]: u, v = v, u # 让u和v处于同一深度 for k in reversed(range(LOG)): if depth[parent[u][k]] >= depth[v]: u = parent[u][k] if u == v: return u for k in reversed(range(LOG)): if parent[u][k] != parent[v][k]: u = parent[u][k] v = parent[v][k] return parent[u][0] # 初始化 LOG = 20 # 根据树的深度调整 parent = [[-1]*LOG for _ in range(n)] depth = [0]*n dfs(root, -1) ``` #### 2. **字符串匹配中的应用** 倍增算法也常用于后缀数组的构建。后缀数组是一种高效的字符串处理工具,而倍增法可以通过逐步扩展当前排序的长度来构建后缀数组,时间复杂度为 $O(n \log n)$。 ### 使用场景 #### 1. **树结构中的 LCA 查询** 倍增算法在树结构中查找两个节点的最近公共祖先时非常高效。该方法通过预处理每个节点的 $2^k$ 祖先信息,使得每次查询只需要对数时间即可完成。 #### 2. **动态规划中的状态转移** 在某些动态规划问题中,状态之间的转移可以通过倍增法进行优化。例如,在区间 DP 中,如果状态转移函数满足一定的性质(如可结合性),则可以使用倍增法来加速状态的更新。 #### 3. **字符串处理** 后缀数组的构建、最长公共前缀(LCP)的计算等问题中,倍增算法被广泛采用。通过逐步增加比较的长度,可以快速构造出完整的后缀数组。 ### 复杂度分析 倍增算法的时间复杂度通常为 $O(n \log n)$,其中 $n$ 是输入的规模。空间复杂度也为 $O(n \log n)$,因为需要存储每个节点的 $2^k$ 阶祖先信息或其他类似的结构。 ### 总结 倍增算法通过预处理和二进制拆分的思想,能够在许多实际问题中显著提升性能。它不仅适用于树结构中的 LCA 查询,还可以应用于字符串处理、动态规划等多个领域。[^4] ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值