数字截断求和 题解
闲来无事发题解
时间限制:1000ms 内存限制:128MB 栈限制:128MB
题目描述
对于一个正整数 X1,不断删除其最后一位数字,依次得到 X2、X3、...、Xn,直到只剩一位数字为止。令 Y = X1 + X2 + ... + Xn。
例如:X1 = 509 时,X2 = 50,X3 = 5,则 Y = 509 + 50 + 5 = 564。
现在给定 Y,请求出原始的 X1。若不存在满足条件的 X1,输出 -1。数据保证若有解则解唯一。
输入格式
一行,一个正整数Y。
输出格式
一行,一个整数X1,或者输出-1。
样例
样例 1 输入:
564
样例 1 输出:
509
样例 2 输入:
565
样例 2 输出:
-1
样例 3 输入:
137174210616796
样例 3 输出:
123456789555123
样例解析
样例1:509 + 50 + 5 = 564,所以X1 = 509。
样例2:不存在满足条件的X1,输出-1。
样例3:大数据测试。
数据规模
1 ≤ Y ≤ 10^15
所谓不开 long long冒青烟,我们观察题目:
找到一个数,每次/10后增加起来=y就是答案
样例解释:
样例3:123456789555123+12345678955512+1234567895551+123456789555+12345678955+1234567895+123456789+12345678+1234567+123456+12345+1234+123+12+1=137174210616796
思路1 暴力枚举
万事皆暴力,我们从1枚举到y,每次都尝试一次,再写一个函数去判断即可
函数判断:
用一个数(i)每次/10再用sum加起来
函数代码:
cpp
long long sumhe(long long x){
long long tmp=0;
while(x>0){
tmp+=x;
x/=10;
}
return tmp;
}
枚举代码:
cpp
cin>>y;
for(long long i=1;i<=y;i++){
if(sumhe(i)==y){
cout<<i;
return 0;
}
}
但是这样子当 y = 101510^{15}1015 时就会超时,因为c++ 1秒只能运行 10910^{9}109 / 1e91e91e9 次
数字截断求和 题解
闲来无事发题解
时间限制:1000ms 内存限制:128MB 栈限制:128MB
题目描述
对于一个正整数 X1,不断删除其最后一位数字,依次得到 X2、X3、...、Xn,直到只剩一位数字为止。令 Y = X1 + X2 + ... + Xn。
例如:X1 = 509 时,X2 = 50,X3 = 5,则 Y = 509 + 50 + 5 = 564。
现在给定 Y,请求出原始的 X1。若不存在满足条件的 X1,输出 -1。数据保证若有解则解唯一。
输入格式
一行,一个正整数Y。
输出格式
一行,一个整数X1,或者输出-1。
样例
样例 1 输入:
564
样例 1 输出:
509
样例 2 输入:
565
样例 2 输出:
-1
样例 3 输入:
137174210616796
样例 3 输出:
123456789555123
样例解析
样例1:509 + 50 + 5 = 564,所以X1 = 509。
样例2:不存在满足条件的X1,输出-1。
样例3:大数据测试。
数据规模
1 ≤ Y ≤ 10^15
所谓不开 long long冒青烟,我们观察题目:
找到一个数,每次/10后增加起来=y就是答案
样例解释:
样例3:123456789555123+12345678955512+1234567895551+123456789555+12345678955+1234567895+123456789+12345678+1234567+123456+12345+1234+123+12+1=137174210616796
思路1 暴力枚举
万事皆暴力,我们从1枚举到y,每次都尝试一次,再写一个函数去判断即可
函数判断:
用一个数(i)每次/10再用sum加起来
函数代码:
cpp
long long sumhe(long long x){
long long tmp=0;
while(x>0){
tmp+=x;
x/=10;
}
return tmp;
}
枚举代码:
cpp
cin>>y;
for(long long i=1;i<=y;i++){
if(sumhe(i)==y){
cout<<i;
return 0;
}
}
但是这样子当 y = 101510^{15}1015 时就会超时,因为c++ 1秒只能运行 10910^{9}109 / 1e91e91e9 次

思路2 二分答案
二分查找科普环节(可跳过)
二分查找就像一种猜数游戏,能够大大优化枚举时间的复杂度
像我们玩的猜数游戏:
A :数字炸弹在1到100内!
B :我猜50
A :小了
B :75?
A :大了
B :62?
A :还是大了!
B :56?
A :小了!
B :59?
A :大了!
B :58
A :蒸蚌!
这就是一次二分查找过程,对比:
枚举:1 -> 2 -> 3 ...-> 答案
二分查找:中间值 ->(中间值调整) 中间值 -> ... ->答案
相比之下,猜1~100,枚举需要100次,而二分查找至于用7次
具体思路:设定两个指针 l,r分别指向左边界与右边界,再设一个mid=(l+r)/2,如果小了就l=mid+1,否则r=mid-1
二分AC代码
cpp
#include<bits/stdc++.h>
using namespace std;
long long y;
long long sumhe(long long x){
long long tmp=0;
while(x>0){
tmp+=x;
x/=10;
}
return tmp;
}
int main(){
cin>>y;
long long l=1,r=y,mid=0,tmp=-1;
while(l<=r){
mid=(l+r)/2;
if(sumhe(mid)==y){
tmp=mid;
break;
}
if(sumhe(mid)<y){
l=mid+1;
}else if(sumhe(mid)>y){
r=mid-1;
}
}
cout<<tmp;
return 0;
}
```
## 思路2 二分答案
### 二分查找科普环节(可跳过)
二分查找就像一种猜数游戏,能够大大优化枚举时间的复杂度
像我们玩的猜数游戏:
**A** :数字炸弹在```1```到```100```内!
**B**:我猜```50```
**A** :小了
**B** :```75```?
**A** :大了
**B** :```62```?
**A** :还是大了!
**B** :```56```?
**A** :小了!
**B** :```59```?
**A** :大了!
**B**:```58```
**A** :蒸蚌!
这就是一次二分查找过程,对比:
枚举:1 -> 2 -> 3 ....-> 答案
二分查找:中间值 ->(中间值调整) 中间值 -> ... ->答案
相比之下,猜1~100,枚举需要100次,而二分查找至于用7次
具体思路:设定两个指针 l,r分别指向左边界与右边界,再设一个```mid=(l+r)/2```,如果小了就```l=mid+1```,否则```r=mid-1```
### 二分AC代码
```cpp
#include<bits/stdc++.h>
using namespace std;
long long y;
long long sumhe(long long x){
long long tmp=0;
while(x>0){
tmp+=x;
x/=10;
}
return tmp;
}
int main(){
cin>>y;
long long l=1,r=y,mid=0,tmp=-1;
while(l<=r){
mid=(l+r)/2;
if(sumhe(mid)==y){
tmp=mid;
break;
}
if(sumhe(mid)<y){
l=mid+1;
}else if(sumhe(mid)>y){
r=mid-1;
}
}
cout<<tmp;
return 0;
}