牛牛选择了一个正整数X,然后把它写在黑板上。然后每一天他会擦掉当前数字的最后一位,直到他擦掉所有数位。 在整个过程中,牛牛会把所有在黑板上出现过的数字记录下来,然后求出他们的总和sum.
例如X = 509, 在黑板上出现过的数字依次是509, 50, 5, 他们的和就是564.
牛牛现在给出一个sum,牛牛想让你求出一个正整数X经过上述过程的结果是sum.
输入包括正整数sum(1 ≤ sum ≤ 10^18)
输出一个正整数,即满足条件的X,如果没有这样的X,输出-1。
564
509
看评论都是说用二分法。我怎么就没想到呢?貌似我用的是“十分法”哈哈。
提供一种极为简单易懂的思路:
就拿题目的564举例:
我们要找到一个数x,经过一系列擦掉最后一位操作后,和为564。
首先要确定x的位数,它一定是三位或两位(如果是四位,结果肯定是四位)。在此我们就假定它是三位数abc(就算最终结果是两位数,那么求出来a=0就可以了)。经过一系列擦操作之后:abc + ab + a = 564,
即:(a * 100 + b * 10 + c) + (a * 10 + b) + (a) =564;
即 :111 * a + 11 * b + 1 * c = 564
我们想要求a、b、c,很简单,a = 564 // 111 = 5("//"表示取整操作)
此时564 - 111 * 5 = 9。接下来要求b:b = 9//11 = 0
此时 9 - 0 * 11 = 9。接下来要求c:c = 9//1 = 9
最终结果5->0->9
扩展到四位数x,它的形式一定是1111 * a + 111 * b + 11 * c + 1* d = x
同理扩展到n位数。
根据上面的思路,代码就简单了:
string = input()
num, res = int(string), ""
for i in range(len(string), 0, -1):
res += str(num // int(i * "1"))
num = num % int(i * "1")
print(res if int(res) < int(string) else -1)如果判断找不到x呢,如果求出来结果比输入的数大,肯定是不对的,此时输出-1
#include<stdio.h>
long long getSum(long long);
int main(){
long long sum,l,r,mid;
//freopen("input.txt","r",stdin);
scanf("%lld",&sum);
for(l=0,r=sum;l+1<r;){
mid=l+(r-l)/2;
if(getSum(mid)==sum){
printf("%lld",mid);
return 0;
}else if(getSum(mid)<sum) l=mid;
else r=mid;
}
if(getSum(l)==sum) printf("%lld",l);
else if(getSum(r)==sum) printf("%lld",r);
else printf("-1");
}
long long getSum(long long x){
long long sum=0;
while(x!=0) sum+=x,x/=(long long)10;
return sum;
}//数据这么大,一看就是二分啦~
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String str = scanner.nextLine();
if(str==null||str.length()==0){
System.out.println("-1");
return;
}
long res = Long.parseLong(str);
List<Long> list = new LinkedList<>();
for (int i = str.length(); i >0 ; i--) {
long listItem = res/num(i);
list.add(listItem);
res = res - listItem*num(i);
}
res=0;
for (int i = 0; i < list.size(); i++) {
if(list.get(i)>9){
System.out.println("-1");
return;
}
res=list.get(i)+res*10;
}
System.out.println(res);
}
public static long num(int len){
long sum = 0;
for (int i = 0; i < len; i++) {
sum=sum*10+1;
}
return sum;
}
}
菜鸡完全想不到二分法,我就是个弟弟
#include <bits/stdc++.h>
using namespace std;
long F(long x){
long s = 0;
while(x){
s += x;
x /= 10;
}
return s;
}
long BS(long s){
long l=s-(s/10)*2, r=s, m, sm;
while(l<=r){
m = (l+r)>>1;
sm = F(m);
if(sm > s)
r = m - 1;
else if(sm < s)
l = m + 1;
else
return m;
}
return -1;
}
int main(){
long s, x;
scanf("%ld", &s);
x = BS(s);
printf("%ld\n", x);
return 0;
} import java.util.Scanner;
public class Main {
public static long process(long cur, long n) {
long sum = cur;
while (cur > 0) {
sum += cur / 10;
cur /= 10;
}
return sum;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
long n = sc.nextLong();
long l = 0;
long r = n;
while (l <= r) {
long mid = l + (r - l) / 2;
if (process(mid, n) == n) {
System.out.println(mid);
return;
} else if (process(mid, n) > n) {
r = mid - 1;
} else {
l = mid + 1;
}
}
System.out.println(-1);
}
}
#include<iostream>
#include<string>
#include<sstream>
#include<queue>
#include<utility>
#include<set>
#include<vector>
#include<map>
#include<stack>
#include<algorithm>
using namespace std;
long long search(long long x,long long target) {
long long y = (x / 100) * 100;//比如x=508,那么就从 500开始搜
for (long long i = y;i < y + 102;++i) {//搜102个数
long long tmp = i;
long long sum = 0;
while (tmp > 0) {
sum += tmp;
tmp /= 10;
}
//cout<<"i= "<<i<<" sum="<<sum<<" target="<<target<<endl;
if (sum -target==0) {
return i ;
}
}
return -1;
}
int main()
{
long long x;
while (cin >> x) {
int cnt = 0;//统计位数
long long tmp = x;
while (tmp > 0) {
++cnt;
tmp /= 10;
}
long double i = 0.1;
long double sum =0.0;//方程中x的系数
for (int k = 0;k < cnt ;++k) {
sum += pow(i, k);
}//比如输入564,sum=1+0.1+0.01
//y=564/1.11=508
long long y = (long long)(x * 1.0 / sum);
cout<<search(y, x)<<endl;
}
return 0;
}
评论区一堆堆的是二分法,菜鸡的我是真的么想出来...面壁中 .....
孤零零地在找规律,最后发现如果 sum为xyzhjk,那么原数可能为xyzhjk-xyzhj 只是可能哈
至于确实是不是,那还得检查;如果不是,那还得继续判断sum是否能被有效表示 见check函数
import java.util.*;
public class Main{
public static void main(String[] args){
try(Scanner in = new Scanner(System.in)){
String sum = in.nextLine();
if(Long.parseLong(sum) >= 1 && Long.parseLong(sum) <= 9) System.out.println(Long.parseLong(sum));
else System.out.println(helper(sum));
}
}
public static long helper(String sum){
int j = sum.length() - 1;
char[] cs = sum.toCharArray();
long sumLong = Long.valueOf(sum);
long ca = Long.valueOf(new String(cs,0,cs.length - 1));
return check(Long.parseLong(sum),sumLong - ca);
}
public static long check(long sum,long v){
long res = 0;
char[] cs = Long.toString(v).toCharArray();
for(int len = cs.length;len > 0;len--){
res += Long.valueOf(new String(cs,0,len));
}
if(res == sum) return v;
if(res > sum){
while(res > sum){
v--;
res = 0;
cs = Long.toString(v).toCharArray();
for(int len = cs.length;len > 0;len--){
res += Long.valueOf(new String(cs,0,len));
}
}
if(res == sum) return v;
else return -1;
}else{
while(res < sum){
v++;
res = 0;
cs = Long.toString(v).toCharArray();
for(int len = cs.length;len > 0;len--){
res += Long.valueOf(new String(cs,0,len));
}
}
if(res == sum) return v;
else return -1;
}
}
}
import java.util.*;
public class Main {
public static long MAX = (long)1e18;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
long in = sc.nextLong();
System.out.println(niuBinarySearch(in, 0, MAX));
}
private static long getNiuSum(long num) {
long ans = 0;
while (num != 0) {
ans += num;
num /= 10;
}
return ans;
}
private static long niuBinarySearch(long target, long fromIndex, long toIndex) {
while (fromIndex < toIndex) {
long mid = (fromIndex + toIndex) >> 1;
long midNiuSum = getNiuSum(mid);
if (midNiuSum == target) {
return mid;
} else if (target > midNiuSum) {
fromIndex = mid+1;
} else if (target < midNiuSum) {
toIndex = mid ;
}
}
return -1;
}
}
本套3道题的C++代码已挂到了我的GitHub(https://github.com/shiqitao/NowCoder-Solutions)
牛客网上的其他题目解答也在持续更新。
#include <iostream>
using namespace std;
long long int csum(long long int num);
int main()
{
long long int sum; cin >> sum;
long long int start = 1, end = sum;
while (start + 1 < end) {
long long int mid = start + (end - start) / 2;
if (csum(mid) == sum) {
cout << mid << endl;
return 0;
}
else if (csum(mid) > sum) end = mid;
else start = mid;
}
if (csum(start) == sum) cout << start << endl;
else if (csum(end) == sum) cout << end << endl;
else cout << -1 << endl;
return 0;
}
long long int csum(long long int num)
{
long long int result = 0;
while (num != 0) {
result += num;
num /= 10;
}
return result;
}
function getNum(n) {
let start = new Date(),
min = n - Math.floor(n / 10),
max = min + Math.floor( [].reduce.call( n.toString(), ( t, i ) => t + +i, 0 ) / 10),
num = -1,
io = num => {
let result = 0;
while (num >= 1) {
result += Math.floor(num);
num /= 10;
}
return result;
};
while (min <= max) {
io(min) === n && (num = min, min = max);
min++;
}
console.log('看看找到没', num)
console.log("所用时间", new Date() - start)
}
import java.math.BigInteger;
import java.util.*;
import java.io.*;
/**
最大值最小问题 常用思路都是二分法,这个题目更容易。反而收到了影响,我一开始没想用二分法
然后看了题解二分 那么当然会写了,但是如果没人说二分 还是不太会。看来二分我还不会去套用model
*/
public class Main{
static long n;
public static void main(String[] args) throws IOException {
Scanner in = new Scanner(System.in);
n = in.nextLong();
long left = 0, right = Long.MAX_VALUE;
while(left < right){
Long mid = (right - left) / 2 + left;
if(check(mid) == 0){
System.out.println(mid);
return;
}else if(check(mid) == 1){
left = mid + 1;
}else {
right = mid;
}
}
System.out.println(-1);
}
static int check(long x){
long sum = 0;
while(x != 0){
sum += x;
x /= 10;
}
if(sum == n) return 0;
return sum < n ? 1 : -1;
}
}
#include <stdio.h>
int main() {
long long a,b;long long temp;long cntl;int i;
while(scanf("%ld",&a) != EOF){
b=a-a/10;
for(i=0;i<18;i++){
cntl=b+i;
temp=0;
while(cntl>0)
{
temp+=cntl;
cntl=cntl/10;
}
if(temp==a)goto out;
}
if(1)printf("%d\n",-1);
else{
out: printf("%ld\n",b+i);
}
}
return 0;
}
#include <stdio.h>
long long sum;
long long f(long long x);
int main()
{
long long n,min,max;
scanf("%lld",&sum);
min = (long long)(((double)sum)/1.2);
max = sum;
while(min<=max)
{
n = (min + max) >> 1;
if(f(n)==sum)
{
printf("%lld\n",n);
return 0;
}
if(f(n)<sum)
min = n + 1;
else
max = n - 1;
}
puts("-1");
return 0;
}
long long f(long long x)
{
long long t=0;
while(x)
{
t += x;
x /= 10;
}
return t;
} while True: try: num = (int)(raw_input()) num2 = num / 10 tmp = num - num2 s = 0 while tmp < num: n = tmp while n > 0: s += n n/=10 if s < num : s = 0 tmp += 1 if s == num : print tmp break if s > num: print -1 break except EOFError: break;
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner s = new Scanner(System.in);
long sum = s.nextLong();
int len = (sum+"").length();
long data = sum;
StringBuffer sb = new StringBuffer();
long num = 0;
for(int i=len; i >0; i--){
long val = sum / getNum(i);
sb.append(val);
num = num + val * getNum(i);
sum %= getNum(i);
}
if(Long.parseLong(sb.toString()) > data){
System.out.println(-1);
}else{
System.out.println(sb.toString());
}
}
public static Long getNum(int n){
StringBuffer sb = new StringBuffer();
while(n-- >0){
sb.append("1");
}
return Long.parseLong(sb.toString());
}
} // 二分法,最后low=middle+1; //这样才保证不会出现low=3,high=4一直平均为3,一直low<high 而跳不出来
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
while(sc.hasNext()){
Cal(sc);
}
}
public static void Cal(Scanner sc){
String nn=sc.next();
long n=Long.parseLong(nn);
long low=0;
long high=n;
long middle=(low+high)/2;
while(high>low) {
long a=res(middle);
if (a==n) {
System.out.println(middle);
return ;
}
if(a>n) {
high=middle;
}
else {
low=middle+1;
}
// middle=(low+high)/2;
middle= (low + high) >> 1;
}
System.out.println(-1);
}
public static long res(long n) {
long sum=0;
while(n!=0){
sum=sum+n;
n=n/10;
}
return sum;
}
}