对于一个整数x,的最小k(分割次数)分割,是在(k<x的位数,x=123位数为3, x=0,位数为1),在位数-1个空格中选出k个空格将元数字分为k+1段,求其各段乘机之和最大的分割乘积。
(注意:对数字x的分割,对于任意分割位置两端必须有数字,即分割所在位置在数字之间,因为在数字两端相当于没有分割,并且任意数x的0,分割>他的k分割K>1<len(数字长度),
证明:
此时存在数字
数字:a..b..
a*10^x+b*10^y > (a*(10^(x-y)) * b*10^y
(a*(10^(x-y)) +1> (a*(10^(x-y))
显然是正确的.
如x=3456,k=2的分割有:
3 4 56 乘积为672
3 45 6 乘积为810
34 5 6 乘积为1020
因此最大的k分割为1020
思路比较明显
数字x,的k分割,相当于数字长度l=len(x) (len(x) 数字的位数) 再l内的k分割, 记为dp[l][k]
dp[l][k]=max(dp[j][k-1]*result[j+1][l]) { j>=1&&j<=l )
最后的结果为dp[len(x)][k]
比较直观,由于只是上机题只考虑x再unsigned int 范围内部,由于上述结论(数字的任意分割乘积小于自身因此结果不会超过unsigned long int)
如果x不是一个数字而是一个数字字符串串的话那么思想不变,加上大数就好了。
下面贴上代码:
滚动数组,要注意计算顺序.
#include <stdio.h>
#include <string.h>
#define max_n 100
typedef unsigned long int ul;
ul x,kk;
ul dp[max_n]={0};
int calculate[max_n]={0};
ul cnt[8]={1,10,100,1000,10000,100000,1000000,10000000};
int getlength(ul num){
int i=1;
while(num>=cnt[i]){
i++;
}
return i;
}
int getNum(ul num,int i,int j){
int len=getlength(num);
return (num%cnt[len-i+1])/cnt[len-j];
}
ul max(ul a,ul b){
return a>b?a:b;
}
int main(){
int i,j,k;
int len;
scanf("%lu%lu",&x,&kk);
len=getlength(x);
for(i=1;i<=len;i++){
dp[i]=getNum(x,1,i);
}
for(i=1;i<=kk;i++){
for(j=len;j>=i+1;j--){
for(k=j-1;k>=i;k--){
if(calculate[j]==0||dp[j]<dp[k]*getNum(x,k+1,j)){
dp[j]=dp[k]*getNum(x,k+1,j);
calculate[j]=1;
}
}
}
memset(calculate,0,sizeof(calculate));
}
printf("%lu\n",dp[len]);
return 0;
}