codeforces-Ed90-E

codeforces-Ed90-E

七月 17, 2020

E. Sum of Digits

题意

给定 n 和 k (1≤n≤150,0≤k≤9) ,找到最小的 x ,使得:

f(x)+f(x+1)+⋯+f(x+k)=n

其中f(x) 表示 x 的十进制数字的和

若不存在x则输出-1

题解

贪心的想:用最少位的数来构造出n

那么尽量用更多的9来减少x的位数才能使得答案最小

注意到n最大150 , 150/9 <= 17 那么所有小于150的n能用f(x)+f(x+1)+⋯+f(x+k)来表示的x一定不超过longlong

而使用9来构造x导致了进位问题 不过题面条件限制k<=9

意味着 x,x+1,x+2,….,x+k最多只进位一次

于是把数x拆分成4个部分来暴力枚举

首先考虑个位数。 因为k<=9所以最直接影响到的是个位数上的数字

其次是个位之前有多少个连续的9。 因为个位数的进位会直接影响到十位以及之前的连续的9

枚举x这两部分的值后可以直接计算k+1个数对答案产生的贡献 sum

具体的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
for(int lastnum=0;lastnum<=9;lastnum++){
for(int suf9=16;suf9>=0;suf9--){
ll sum=0,cnt=1;ll temp=lastnum;
while(cnt<=suf9){
temp+=9*qpow(10,cnt);
cnt++;
}
//cout<<1<<" "<<temp<<endl;
for(int i=0;i<=k;i++){
if(lastnum+i<10)sum+=(9*suf9+lastnum+i);
else sum+=(1+(lastnum+i)%10);
}
/*后续操作*/
}
}

然后rest=n-sum

如果rest<=8那么当前枚举的符合要求的x首位就是8 后面接上枚举的连续的9和个位数值

否则 答案x需要在最前面插入一个8(因为suf9讨论的是个位进位会直接影响到的十进制位,8是最大的且不受后面进位影响的数) 然后贪心的填充余下 更高位的数

具体的

1
2
3
4
5
6
7
8
9
10
11
12
if(n<sum)continue;
if((n-sum)%(k+1))continue;///剩下的数若不能被(k+1)个数平分则表示当前枚举的x一定不是答案
ll rest=(n-sum)/(k+1);
if(rest>8)temp+=8*qpow(10,cnt),cnt++,rest-=8;
while(rest>8){///贪心的填充用尽量大的数9来填充n-sum余下的值让x的位数更小
temp+=9*qpow(10,cnt);
cnt++;
rest-=9;
}
//cout<<2<<" "<<temp<<endl;
temp+=rest*qpow(10,cnt);
ans=min(ans,temp);

于是这样贪心构造出最后的x一定符合

首位 9999 8 9999 末位 这种形式

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> P;
#define endl '\n'
#define Turnoff std::ios::sync_with_stdio(false)

const int mod=2e3;
const int Max=2e6+5;

/*
*/
ll qpow(ll x,ll y){
ll ans=1;
while(y){
if(y&1)ans*=x;
x*=x;y>>=1;
}
return ans;
}

int main(){
//Turnoff;
int t;cin>>t;
while(t--){
int n,k;cin>>n>>k;ll ans=1e18;
for(int lastnum=0;lastnum<=9;lastnum++){
for(int suf9=16;suf9>=0;suf9--){
ll sum=0,cnt=1;ll temp=lastnum;
while(cnt<=suf9){
temp+=9*qpow(10,cnt);
cnt++;
}
//cout<<1<<" "<<temp<<endl;
for(int i=0;i<=k;i++){
if(lastnum+i<10)sum+=(9*suf9+lastnum+i);
else sum+=(1+(lastnum+i)%10);
}
if(n<sum)continue;
if((n-sum)%(k+1))continue;
ll rest=(n-sum)/(k+1);
if(rest>8)temp+=8*qpow(10,cnt),cnt++,rest-=8;
while(rest>8){
temp+=9*qpow(10,cnt);
cnt++;
rest-=9;
}
//cout<<2<<" "<<temp<<endl;
temp+=rest*qpow(10,cnt);
ans=min(ans,temp);
}
}
//cout<<endl;
if(ans!=1e18)cout<<ans<<endl;
else cout<<-1<<endl;
}
}