P1018乘积最大

原题链接

P1018

题目大意

有一个长的为 n ( 6 ≤ n ≤ 40 ) n(6\le n\le 40) n(6n40)的字符串,你要在其中任意添加 k ( 1 ≤ k ≤ 6 ) k(1\le k\le 6) k(1k6)个乘号,求得到的最大值是多少。

结题思路

如果使用暴力枚举,时间复杂度就会为: O ( 4 n ) O(4^n) O(4n),超时。这时候,我们考虑动态规划。假如我们设 f ( n , k ) f_{(n,k)} f(n,k)表示前 n n n个位置放 k k k个乘号的最大结果,设 r ( i , j ) r_{(i,j)} r(i,j)表示字符串中第 i ∼ j i\sim j ij位的数字,则:
f ( i , j ) = { j = 0       r ( i , j ) max ⁡ i ≤ k < j ( f ( k , i ) , f ( k , i ) × r ( k , j ) ) f_{(i,j)}=\left\{\begin{matrix}j=0\ \ \ \ \ r_{(i,j)} \\ \max_{i\le k<j} (f_{(k,i)},f_{(k,i)}\times r_{(k,j)}) \end{matrix}\right. f(i,j)={j=0     r(i,j)maxik<j(f(k,i),f(k,i)×r(k,j))
就为状态转移方程,最终的答案就被存储在 f ( n , k ) f_{(n,k)} f(n,k)中。

代码实现

#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
string s,r[100][100],f[100][100];
int n,k;
string cheng(string s1,string s2)//字符串高精乘法
{
	if(s1=="0"||s2=="0") return "0";//任何数乘0等于0
	string s3="",s4="",ans="",re="";
	long long len1=0,len2=0,jw=0,t=0,ansi=0;
	len1=s1.size();
	len2=s2.size();
	for(long long i=1;i<=len2+1;i++) s1='0'+s1;//补前缀0
	for(long long i=len1+len2;i>=0;i--) s3+=s1[i],ans+="00";//防止RE
	for(long long i=1;i<=len1+1;i++) s2='0'+s2;//补前缀0
	for(long long i=len1+len2;i>=0;i--) s4+=s2[i];
	long long s3x=0,s4x=0;
	while(s3[s3x]=='0') s3x++;
	while(s4[s4x]=='0') s4x++;
	s3=s3.substr(s3x,s3.size()-s3x);
	s4=s4.substr(s4x,s4.size()-s4x);
	for(long long i=0;i<s3.size();i++)
		for(long long j=0;j<s4.size();j++){
			t=int(s3[i]-'0')*int(s4[j]-'0')+jw;
			ansi=(t+(ans[i+j]-'0'));//转数字进行计算
			jw=ansi/10;
			ans[i+j]=char(ansi%10+'0');//转回字符存储
		}
	for(long long i=1;i<=s3x+s4x;i++) ans="0"+ans;
	long long b=ans.size()-1;
	while(b>=1&&ans[b]=='0') b--;//去前缀0
	for(long long i=b;i>=0;i--) re+=ans[i];//倒序遍历
	return re;
}
bool q_bigger_h_setup(string q,string h)
{
	if(q.size()!=h.size()) return q.size()>h.size();//比较大小
	else return q>h;//比较大小
}
string _max(string a,string b){//返回较大字符串
	if(q_bigger_h_setup(a,b))
		return a;
	return b;
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin>>n>>k;
	cin>>s;
	for(int i=0;i<n;i++)
		for(int j=i;j<n;j++)
			r[i][j]=s.substr(i,j-i+1);
	for(int i=1;i<=k;i++)
		for(int j=1;j<=n;j++)
			f[i][j]="0";
	for(int i=1;i<=n;i++)//初始化
		f[i][0]=r[0][i-1];
	for(int k2=1;k2<=k;k2++)//动态规划
		for(int i=k2+1;i<=n-k+k2;i++)
			for(int j=k2;j<i;j++)
				f[i][k2]=_max(f[i][k2],cheng(f[j][k2-1],r[j][i-1]));
	cout<<f[n][k];
	return 0;
}

样例

输入

4  2
1231

输出

62
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值