- 总时间限制:
- 1000ms
- 内存限制:
- 65536kB
- 描述
-
今年是国际数学联盟确定的“2000——世界数学年”,又恰逢我国著名数学家华罗庚先生诞辰90周年。在华罗庚先生的家乡江苏金坛,组织了一场别开生面的数学智力竞赛的活动,你的一个好朋友XZ也有幸得以参加。活动中,主持人给所有参加活动的选手出了这样一道题目:
设有一个长度为N的数字串,要求选手使用K个乘号将它分成K+1个部分,找出一种分法,使得这K+1个部分的乘积能够为最大。
同时,为了帮助选手能够正确理解题意,主持人还举了如下的一个例子:
有一个数字串:312,当N=3,K=1时会有以下两种分法:
1) 3*12=36
2) 31*2=62
这时,符合题目要求的结果是:31*2=62
现在,请你帮助你的好朋友XZ设计一个程序,求得正确的答案。
- 输入
- 程序的输入共有两行:
第一行共有2个自然数N,K(6≤N≤40,1≤K≤6)
第二行是一个长度为N的数字串。 - 输出
- 输出所求得的最大乘积(一个自然数)。(保证最终答案不超过int范围)
- 样例输入
-
4 2 1231
- 样例输出
-
62
- 来源
- NOIP2000复赛 普及组 第三题
- 【思路】
- 最优问题 动态规划 递推思路
- 有k个决策 每放入一个*为一次决策;
- 进行划分的数的位数最少也要是乘号的个数+1,循环到n位数‘;
- 每次看最后一个乘号后还有几位数;
- 然后枚举最后一个乘号后面的数有几位
- 【代码】
-
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 using namespace std; 5 long long a[30][30],f[30][30];//数组a[i][j]记录从第i位到第j位的数的大小 6 int main() //f[i][j]为前i位数分j个乘号的最大值 7 { 8 int n,k; 9 long long s; 10 scanf("%d%d%lld",&n,&k,&s);//输入位数,乘号的个数,数字串 11 for(int i=n;i>=1;i--) 12 {//如果s是长整型的,数组a也要是长整型的 13 a[i][i]=s%10;//从第i位到第i位就是这个数本身; 14 // cout<<a[i][i]<<endl; 15 s/=10;// 16 } 17 for(int i=2;i<=n;i++) 18 for(int j=i-1;j>=1;j--) 19 a[j][i]=a[j][i-1]*10+a[i][i];//计算每一位到每一位,因为上面已经推出本身到本身,所以任意两位之间的距离都能推出来 20 for(int i=1;i<=n;i++)//特殊处理一下没有乘号的情况 21 f[i][0]=a[1][i];//前i个数分到0个乘号的值就是第1-i这个数本身; 22 for(int i=1;i<=k;i++)//分为k个阶段;即插入k个乘号;每插入一个乘号为一个决策阶段; 23 for(int j=i+1;j<=n;j++)//判断一下最后一个乘号后有几位数(当第i个乘号被分配时,最少有i+1个数, 24 //所以循环从i+1开始) 25 for(int m=i;m<j;m++) 26 f[j][i]=max(f[j][i],f[m][i-1]*a[m+1][j]);//前j个数分配i个乘号取最大值,前m个数分配i-1个乘号的值 27 //再乘以最后一个乘号后的值 28 printf("%lld\n",f[n][k]);//输出n个数分配k个乘号的值 29 return 0; 30 }
时间: 2024-10-12 10:17:20