题意
定义一个数是上升的,当其每个数位上的数不小于比它数位高的数
比如11233
然后给你一个数N(
N
<
=
1
0
500000
N<=10^{500000}
N<=10500000)
求它最少能拆成几个上升的数的和
题解
首先有几个性质需要发现
第一个是对于一个上升的数,它一定可以写成不超过9个1111111…结构的数的和
也即是说,他一定能写成恰好9个结构为
1
0
p
−
1
9
\frac{10^p-1}{9}
910p−1的和
假如说答案为k,那么
N
=
∑
i
=
1
9
k
1
0
p
i
−
1
9
N=\sum_{i=1}^{9k}\frac{10^{p_i}-1}{9}
N=i=1∑9k910pi−1
移项,可有
9
N
+
9
k
=
∑
i
=
1
9
k
1
0
p
i
9N+9k=\sum_{i=1}^{9k}10^{p_i}
9N+9k=i=1∑9k10pi
可以证明的是,然而我觉得我讲不清楚
9
N
+
9
k
的
数
位
和
<
=
9
k
9N+9k的数位和<=9k
9N+9k的数位和<=9k是上述等式成立的充要条件
所以我们判断这个即可
又由于,比如我们可以一直减去?9999999的结构的东西一次操作就一定可以削去一位,所以答案应该不会大于L
所以我们从小到大枚举k即可
时间复杂度
O
(
L
)
O(L)
O(L)
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int L=500005,M=500005;
typedef long long ll;
const int base=10;
struct BigInt{
int a[M];
int len;
BigInt(){}
BigInt(char *s){
memset(a,0,sizeof a);
len=strlen(s+1);
for(int i=len;i>=1;i--)
a[i]=s[len-i+1]-'0';
}
};
int ans;
void operator +=(BigInt& x,int y){
x.a[1]+=y;
ans+=y;
for(int i=1;i<=x.len;i++){
if(x.a[i]>=base){
if(i==x.len)
x.len++;
ans-=x.a[i];
ans-=x.a[i+1];
x.a[i+1]++;
x.a[i]-=base;
ans+=x.a[i];
ans+=x.a[i+1];
}
else
break;
}
}
BigInt operator *(BigInt x,int y){
int r=0;
for(int i=1;i<=x.len;i++){
x.a[i]*=y;
x.a[i]+=r;
if(x.a[i]>=base){
r=x.a[i]/base;
x.a[i]%=base;
}
else
r=0;
}
x.len++;
x.a[x.len]+=r;
while(x.len>0&&x.a[x.len]==0)
x.len--;
return x;
}
int sum(BigInt x){
int res=0;
for(int i=1;i<=x.len;i++){
res+=x.a[i];
}
return res;
}
char s[L];
int main()
{
//freopen("z.in","r",stdin);
scanf("%s",s+1);
BigInt x(s);
x=x*9;
ans=sum(x);
for(int k=1;;k++){
x+=9;
//if(k%10000==0)
// puts("!");
if(ans<=9*k){
printf("%d\n",k);
return 0;
}
}
}