洛谷 P1018乘积最大题解--zhengjun

题目描述

今年是国际数学联盟确定的“ \(2000\)――世界数学年”,又恰逢我国著名数学家华罗庚先生诞辰\(90\)周年。在华罗庚先生的家乡江苏金坛,组织了一场别开生面的数学智力竞赛的活动,你的一个好朋友\(XZ\)也有幸得以参加。活动中,主持人给所有参加活动的选手出了这样一道题目:

设有一个长度为\(N\)的数字串,要求选手使用\(K\)个乘号将它分成\(K+1\)个部分,找出一种分法,使得这\(K+1\)个部分的乘积能够为最大。

同时,为了帮助选手能够正确理解题意,主持人还举了如下的一个例子:

有一个数字串:\(312\), 当\(N=3,K=1\)时会有以下两种分法:

  1. \(3 \times 12=36\)
  2. \(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;
}

谢谢--zhengjun_记得打赞

posted @ 2022-06-10 18:40  A_zjzj  阅读(116)  评论(0编辑  收藏  举报