洛谷 P1018乘积最大题解--zhengjun
题目描述
今年是国际数学联盟确定的“ \(2000\)――世界数学年”,又恰逢我国著名数学家华罗庚先生诞辰\(90\)周年。在华罗庚先生的家乡江苏金坛,组织了一场别开生面的数学智力竞赛的活动,你的一个好朋友\(XZ\)也有幸得以参加。活动中,主持人给所有参加活动的选手出了这样一道题目:
设有一个长度为\(N\)的数字串,要求选手使用\(K\)个乘号将它分成\(K+1\)个部分,找出一种分法,使得这\(K+1\)个部分的乘积能够为最大。
同时,为了帮助选手能够正确理解题意,主持人还举了如下的一个例子:
有一个数字串:\(312\), 当\(N=3,K=1\)时会有以下两种分法:
- \(3 \times 12=36\)
- \(31 \times 2=62\)
这时,符合题目要求的结果是: \(31 \times 2 = 62\)
现在,请你帮助你的好朋友\(XZ\)设计一个程序,求得正确的答案。
输入格式
程序的输入共有两行:
第一行共有\(2\)个自然数\(N,K\)(\(6\le N\le 40,1\le K\le 6\))
第二行是一个长度为\(N\)的数字串。
输出格式
结果显示在屏幕上,相对于输入,应输出所求得的最大乘积(一个自然数)。
输入输出样例
输入 #1
4 2
1231
输出 #1
62
说明/提示
\(NOIP\ 2000\) 提高组第二题
思路
首先,这是一道动态规划题应该很容易就判断出来。
属于区间 \(dp\) 。
\(f_{i,j}\) 表示前 \(i\) 个数字中插入 \(j\) 个 \(\times\) 号的最大乘积。
初始值:
显然:\(j=0\) 时,\(f_{i,j}=S_1\cdot\cdot\cdot S_j;i\le j\) 时,\(f_{i,j}=0;\)
对于其他情况,就枚举最后一个\(\times\)号的位置和用了几个\(\times\) 号,转移方程就是\(f_{i,j}=max\{f_{k,j-1}\times S_1\cdot\cdot\cdot S_j\}\)
最后,本题还要高精度,你们不想打就直接拿我的模板吧。
上代码
#include<bits/stdc++.h>
using namespace std;
/*************************以下为模板***************************/
#define maxn 10005
struct bignum {
int len,s[maxn];
char flag;
bignum() {
len=1;
flag='+';
memset(s,0,sizeof(s));
}
bignum (int num) {
*this=num;
}
bignum (const char *num) {
*this=num;
}
bignum operator = (const char *a) {
len=strlen(a);
for (int i=1; i<=len; ++i)
s[i]=a[len-i]-'0';
return *this;
}
bignum operator = (const int num) {
char a[maxn];
sprintf(a,"%d",num);
*this=a;
return *this;
}
bignum operator + (const bignum &a) {
bignum c;
c.len=max(len,a.len)+1;
for (int i=1; i<c.len; ++i) {
c.s[i]+=(s[i]+a.s[i]);
c.s[i+1]+=c.s[i]/10;
c.s[i]%=10;
}
if (c.s[c.len]==0)
c.len--;
return c;
}
bignum operator += (const bignum &a) {
*this=*this+a;
return *this;
}
bignum operator * (const bignum &a) {
bignum c;
c.len+=(len+a.len);
for (int i=1; i<=len; ++i)
for (int j=1; j<=a.len; ++j) {
c.s[i+j-1]+=(s[i]*a.s[j]);
c.s[i+j]+=(c.s[i+j-1]/10);
c.s[i+j-1]%=10;
}
while (c.s[c.len]==0)
c.len--;
return c;
}
bignum operator *= (const bignum &a) {
*this=(*this) * a;
return *this;
}
bool operator < (const bignum &a) const {
if (len!=a.len)
return len<a.len;
for (int i=len; i>=1; --i)
if (s[i]!=a.s[i])
return s[i]<a.s[i];
return false;
}
bool operator > (const bignum &a) const {
return a<*this;
}
bool operator <= (const bignum &a) const {
return !(*this>a);
}
bool operator >= (const bignum &a) const {
return !(*this<a);
}
bool operator == (const bignum &a) const {
return !((*this<a) || (*this>a));
}
bool operator != (const bignum &a) const {
return !(*this==a);
}
void change (bignum &a,bignum &b) {
bignum tmp=a;
a=b;
b=tmp;
}
bignum operator - (const bignum &a) const {
bignum b=*this,c;
if (b<a) {
c.flag='-';
c.len=a.len;
for (int i=1; i<=c.len; ++i) {
c.s[i]+=(a.s[i]-b.s[i]);
if (c.s[i]<0) {
c.s[i]+=10;
c.s[i+1]-=1;
}
}
while (c.len==0)
c.len--;
return c;
}
c.len=b.len;
for (int i=1; i<=c.len; ++i) {
c.s[i]+=(b.s[i]-a.s[i]);
if (c.s[i]<0) {
c.s[i]+=10;
c.s[i+1]-=1;
}
}
while (c.len==0)
c.len--;
return c;
}
bignum operator -= (const bignum &a) {
*this=(*this)-a;
return *this;
}
bignum operator / (const int n) {
bignum c,b=*this;
c.len=b.len;
int x=0;
for (int i=1; i<=n; ++i) {
c.s[i]=(x*10+b.s[i])/n;
x=(x*10+b.s[i])%n;
}
while (c.s[c.len]==0)
c.len--;
return c;
}
bignum operator /= (const int a) {
*this=*this/a;
return *this;
}
};
ostream& operator << (ostream &out,const bignum &x) {
for (int i=x.len; i>=1; --i)
printf("%d",x.s[i]);
return out;
}
bignum bigmax(const bignum &a,const bignum &b){
return a>b?a:b;
}
/*************************以上为模板***************************/
int n,k;
char s[50];
bignum f[50][10],a[50][50];
int main() {
scanf("%d%d",&n,&k);
scanf("%s",s+1);
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
a[i][j]=a[i][j-1]*10+(s[j]-'0');
for(int i=1;i<=n;i++){
f[i][0]=a[1][i];
for(int j=1;j<=k;j++)
for(int l=j;l<i;l++)
f[i][j]=bigmax(f[i][j],f[l][j-1]*a[l+1][i]);
}
cout<<f[n][k];
return 0;
}