CodeForces_1375E Sum of Digits(暴力+贪心)

Sum of Digits

time limit per test:2 seconds
memory limit per test:512 megabytes
Problem Description

Let f ( x ) f(x) f(x) be the sum of digits of a decimal number x.

Find the smallest non-negative integer x x x such that f ( x ) + f ( x + 1 ) + ⋯ + f ( x + k ) = n f(x)+f(x+1)+⋯+f(x+k)=n f(x)+f(x+1)++f(x+k)=n.

Input

The first line contains one integer t t t ( 1 ≤ t ≤ 150 1≤t≤150 1t150) — the number of test cases.

Each test case consists of one line containing two integers n n n and k k k ( 1 ≤ n ≤ 150 1≤n≤150 1n150, 0 ≤ k ≤ 9 0≤k≤9 0k9).

Output

For each test case, print one integer without leading zeroes. If there is no such x x x that f ( x ) + f ( x + 1 ) + ⋯ + f ( x + k ) = n f(x)+f(x+1)+⋯+f(x+k)=n f(x)+f(x+1)++f(x+k)=n, print − 1 −1 1; otherwise, print the minimum x x x meeting that constraint.

Sample Input

7
1 0
1 1
42 7
13 7
99 1
99 0
99 2

Sample Output

1
0
4
-1
599998
99999999999
7997

题意

f ( x ) f(x) f(x)等于x各位数字和。给定n和k,求最小的x满足 f ( x ) + f ( x + 1 ) + ⋯ + f ( x + k ) = n f(x)+f(x+1)+⋯+f(x+k)=n f(x)+f(x+1)++f(x+k)=n

题解

x,x+1, … , x+k,是连续的,所以满足条件的x,连续的数中要么只有最后一位不同,要么会存在进位。
x必定为abc形式,其中a代表数位和为 n − 9 ∗ b − c n-9*b-c n9bc的最小的数,b为若干个9(可以为0个),c为个位。

枚举c,求出 x x x x + k x+k x+k个位数上的和记为m。
c + k < 10 c+k<10 c+k<10,则不会存在进位,则c固定后,贪心使a最小即可(从低位到高位尽可能放9)。
c + k ≥ 10 c+k\ge10 c+k10,则枚举b部分,设9的个数为 j j j,则进位前,共有 10 − c 10-c 10c个数,其对于结果的贡献为 9 ∗ j ∗ ( 10 − c ) 9*j*(10-c) 9j(10c);进位后,共有 ( c + k ) % 10 + 1 (c+k)\%10+1 (c+k)%10+1个数,b部分由于进位都变为0,则a部分相比之前,数位和多1。此时x的b,c部分已知,求a部分即可。

注意:
确定b,c部分数位和mm后,(n-mm)可能不能整除(k+1)。
最终结果x在LL范围内,但枚举时,则有部分结果会爆LL,可以考虑用字符串处理x。

#include<stdio.h>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>
#include<queue>
#include<iterator>
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define eps 1e-6
   
using namespace std;
typedef long long LL;   
typedef pair<int, int> P;
const int maxn = 200100;
const int mod = 998244353;
LL solve(int n, int k);

int main()
{
    int n, m, i, k, t;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d %d", &n, &k);
        printf("%I64d\n", solve(n, k));
    }
    return 0;
}

LL solve(int n, int k)
{
    int i, j, a, m, mm, ss;
    LL ans = LLINF, x, tmp;
    for(i=0;i<10;i++){
        
        m = i%10;
        for(j=1;j<=k;j++)
          m += (i+j)%10;

        if(i+k < 10){
            if(n < m || (n-m)%(k+1) != 0)continue;
            ss = (n-m)/(k+1);
            x = i, tmp = 10;
            while(ss){
                x += min(ss, 9)*tmp;
                tmp *= 10, ss -= min(ss, 9);
            }
            ans = min(ans, x);
            continue;
        }
        for(j=0;j<13;j++){
            if(i+k >= 10) mm = m+9*j*(10-i)+(i+k)%10+1;
            else mm = m+9*j*(k+1);

            if(mm <= n && (n-mm)%(k+1) == 0){
                x = i, tmp = 10;
                for(a=1;a<=j;a++){
                    x += 9*tmp;
                    tmp *= 10;
                }
                int ss = (n-m)/(k+1);
                x += min(ss, 8)*tmp;
                tmp *= 10, ss -= min(ss, 8);
                //因为中间结果可能爆LL,所以不科学的用tmp<1e18处理爆LL的情况
                while(ss && tmp < 1e18){
                    x += min(ss, 9)*tmp;
                    tmp *= 10, ss -= min(ss, 9);
                }
                if(!ss)ans = min(ans, x);
            }
        }  
    }
    if(ans == LLINF)return -1;
    else return ans;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值