高精度写了半天
dp[i][j]代表前i个数字放j个加号的最小值。转移的时候枚举在第k个数字后放加号,那么k最大在i-1后放加号,最小在第j个数后面放加号。
O(i^2 * j)复杂度
1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 5 struct bigN{ 6 int a[55],length;//从低位到高位 7 bigN(int num[],int len){//num是从高位到低位 8 memset(a,0,sizeof(a)); 9 length = len; 10 for(int i=0;i<len;i++) a[i]=num[len-i-1]; 11 } 12 bigN(){ 13 length=0; 14 memset(a,0,sizeof(a)); 15 } 16 bigN operator + (bigN n1){ 17 bigN ans; 18 ans.length = max(n1.length,length); 19 for(int i=0;i<ans.length;i++){ 20 ans.a[i] += a[i] + n1.a[i]; 21 ans.a[i+1] += ans.a[i]/10; 22 ans.a[i]%=10; 23 } 24 if(ans.a[ans.length]!=0) ans.length++; 25 return ans; 26 } 27 bool operator < (bigN n1){//this是不是比n1小 28 if( length>n1.length ) return false; 29 else if(length<n1.length) return true; 30 for(int i=length-1;i>=0;i--){//从高位比到低位 31 if( a[i]>n1.a[i] ) return false; 32 else if( n1.a[i]>a[i] ) return true; 33 } 34 //相等 35 return false; 36 } 37 }memo[55][55]; 38 ostream& operator<< (ostream& os,const bigN& x){ 39 for(int i=x.length-1;i>=0;i--) os<<x.a[i]; 40 return os; 41 } 42 43 bigN min(bigN n1,bigN n2){ 44 if(n1<n2) return n1; 45 return n2; 46 } 47 48 int s[55]; 49 bigN dp(int i,int j){//前i个数字之间放j个加号的最小值 50 //cout<<i<<" "<<j<<endl; 51 if(memo[i][j].length!=0) return memo[i][j]; 52 if(i-1==j){ 53 bigN an; 54 for(int i1=1;i1<=i;i1++) an=an+bigN(s+i1,1); 55 return memo[i][j]=an; 56 } 57 if(j==0) return memo[i][j]=bigN(s+1,i); 58 59 //枚举第j个加号放在第k个数字后 60 bigN ans; ans.length=100; 61 for(int k=j;k<=i-1;k++){ 62 bigN cnt = dp(k,j-1)+bigN(s+k+1,i-k); 63 ans = min(ans, cnt ); 64 } 65 66 return memo[i][j]=ans; 67 } 68 69 70 int main(){ 71 int m; 72 while( scanf("%d",&m)!=EOF ){ 73 string s1; cin>>s1; 74 for(int i=0;i<s1.length();i++) s[i+1]=int(s1[i])-48; 75 76 for(int i=0;i<=54;i++) 77 for(int j=0;j<=54;j++) memo[i][j]=bigN(); 78 79 cout<<dp(s1.length(),m)<<endl; 80 } 81 82 return 0; 83 }