整数划分

来源:互联网 发布:iphone6网络连接不上 编辑:程序博客网 时间:2024/05/16 09:23

整数划分


Description

如何把一个正整数 NN 长度<20)划分为MM>1)个部分,使这 N 个部分的乘积最大。
NM 从键盘输入,输出最大值及一种划分方式。


Input

第一行一个正整数 T ( T<=10000),表示有 T 组数据。
接下来 T 行每行两个正整数 NM


Output

对于每组数据
第一行输出最大值。
第二行输出划分方案,将 N 按顺序分成 M 个数输出,两个数之间用空格格开。


Sample Input

1
199 2


Sample Output

171
19 9


Solution

fi,j 表示前 i 位放 j 个乘号的方案数,则

fi,j=MAX{fk,j1Ak+1,i}

其中 Ai,j 表示第 ij 位组成的数字。
至于求方案,则记录每次的决策即可。


Code

#include <iostream>#include <cstdio>#include <cstring>#define Max(x,y) ((x)>(y)?(x):(y))#define LL long longusing namespace std;char n[50];LL m;LL a[50][50];LL f[50][50];LL g[50][50];LL nxt[50];void work(LL x,LL y){    if(g[x][y]==-1)return;    nxt[++nxt[0]]=g[x][y];    work(g[x][y],y-1);}int main(){    freopen("separate.in","r",stdin);    freopen("separate.out","w",stdout);    LL t;    scanf("%lld",&t);    while(t--){        nxt[0]=0;        memset(g,-1,sizeof g);        memset(f,-1,sizeof f);        scanf("%s%lld",n,&m);m--;        LL l=strlen(n);        for(LL i=0;i<l;i++){            a[i][i]=n[i]-'0';            for(LL j=i+1;j<l;j++)                a[i][j]=a[i][j-1]*10+n[j]-'0';        }        for(LL i=0;i<l;i++){            f[i][0]=a[0][i];            g[i][0]=-1;        }        for(LL i=0;i<l;i++)            for(LL j=1;j<=m;j++)                for(LL k=0;k<i;k++){                    if(f[k][j-1]!=-1&&f[k][j-1]*a[k+1][i]>f[i][j]){                        f[i][j]=f[k][j-1]*a[k+1][i];                        g[i][j]=k;                    }                }        printf("%lld\n",f[l-1][m]);        work(l-1,m);        for(LL i=0;i<l;i++){            printf("%c",n[i]);            if(nxt[0]!=0&&i==nxt[nxt[0]]){                printf(" ");                nxt[0]--;            }        }        printf("\n");    }    return 0;}
0 0