1. 程式人生 > >AGC011 E Increasing Numbers

AGC011 E Increasing Numbers

題意

定義一個數是上升的,當其每個數位上的數不小於比它數位高的數 比如11233 然後給你一個數N(N<=10500000N<=10^{500000}) 求它最少能拆成幾個上升的數的和

題解

首先有幾個性質需要發現 第一個是對於一個上升的數,它一定可以寫成不超過9個1111111…結構的數的和 也即是說,他一定能寫成恰好9個結構為10p19\frac{10^p-1}{9}的和 假如說答案為k,那麼N=i=19k10pi19N=\sum_{i=1}^{9k}\frac{10^{p_i}-1}{9} 移項,可有 9N+9k=i=19

k10pi9N+9k=\sum_{i=1}^{9k}10^{p_i} 可以證明的是,然而我覺得我講不清楚 9N+9k<=9k9N+9k的數位和<=9k是上述等式成立的充要條件 所以我們判斷這個即可 又由於,我又證不來了,比較顯然的是,答案應該是L級別的 所以我們從小到大列舉k即可 時間複雜度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; } } }