题意:
如果一个十进制非负整数的所有数位从高位到低位是不减的,我们称它为“上升数”,例如1558,11,3,0都是上升数,而10,20170312则不是;
给定整数N,求最小的k使得N能被表示为k个上升数之和。
$1\leq N\leq 10^{500000}$
题解:
一个结论:每个上升数必定能被分解为九个全一数的和;
所谓“全一数”就是指1,1111,11111111这种每一位数都为1的数(包括0),证明显然。
设N可以被分解成K个全一数之和,显然答案$k=\lceil\frac{K}{9}\rceil$;
由于全一数不好处理,我们可以把一个长度为$l$的全一数变成$\frac{(10^{l+1}-1)}{9}$,那么有:
$N=\sum\limits_{i=1}^{K}\frac{(10^x)}{9}$(此处$x$代表不确定的位数)
$9N=\sum\limits_{i=1}^{K}(10^x-1)$
$9N+K=\sum\limits_{i=1}^{K}10^x$
这个式子是什么意思呢?如果不考虑进位,右边每一项都会使数位和+1,那么总体就说明$9N+K$的数位和等于$K$的数位和,此时$K$一定是9的倍数;
如果考虑进位,那么每进一位数位和就会减少9,因此$K$仍然要是9的倍数。
由于答案最多不会超过N的位数,枚举k,写个高精度乱做就行了。。。注意加法的时候没有进位就要break,这样是均摊$O(1)$的,否则是$O(n^2)$的。
代码:
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #define inf 2147483647
8 #define eps 1e-9
9 using namespace std;
10 typedef long long ll;
11 int n,tot,a[800001];
12 char s[500001];
13 void mul(int a[],int &n,int k){
14 int p=0;
15 tot=0;
16 for(int i=1;i<=n;i++){
17 p=a[i]*k+p;
18 a[i]=p%10;
19 tot+=a[i];
20 p/=10;
21 }
22 if(p)a[++n]=p;
23 tot+=p;
24 }
25 void add(int a[],int &n,int k){
26 int p=0;
27 tot-=a[1];
28 a[1]+=k;
29 p=a[1]/10;
30 a[1]%=10;
31 tot+=a[1];
32 for(int i=2;i<=n;i++){
33 tot-=a[i];
34 a[i]+=p;
35 p=a[i]/10;
36 a[i]%=10;
37 tot+=a[i];
38 if(!p)break;
39 }
40 if(p)a[++n]=p;
41 tot+=p;
42 }
43 int main(){
44 scanf("%s",s);
45 n=strlen(s);
46 for(int i=1;i<=n;i++){
47 a[i]=s[n-i]-'0';
48 }
49 mul(a,n,9);
50 for(int i=1;i<=n;i++){
51 add(a,n,9);
52 if(tot%9==0&&i*9>=tot)return printf("%d",i),0;
53 }
54 return 0;
55 }