2021-01-17

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

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

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

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

3 \times 12=363×12=36
31 \times 2=6231×2=62
这时,符合题目要求的结果是: 31 \times 2 = 6231×2=62

现在,请你帮助你的好朋友 XZ 设计一个程序,求得正确的答案。

输入格式
程序的输入共有两行:

第一行共有 22 个自然数 N,KN,K(6≤N≤40,1≤K≤66≤N≤40,1≤K≤6)

第二行是一个长度为 NN 的数字串。

输出格式
结果显示在屏幕上,相对于输入,应输出所求得的最大乘积(一个自然数)。
原题链接:https://www.luogu.com.cn/problem/P1018
我的代码:

#include <cstdio>  
#include <cstring>  
#include <algorithm>  
using namespace std;  
const int power = 4; //压位    
const int base = 10000; 
const int MAXL = 106;  
struct num //高精度模板,很好理解的 
{  
    int a[MAXL];  
    num() {memset(a,0,sizeof a);} 
    num(char *s)                                  
    {  
        memset(a, 0, sizeof(a));  
        int len = strlen(s);  
        a[0] = (len+power-1) / power;                     
        for (int i=0, t=0, w; i < len ;w *= 10, ++i)          
        {  
            if (i % power == 0) { w = 1, ++t; }  
            a[t] += w * (s[i]-'0');  
        }  
    }  
    void add(int k) { if (k || a[0]) a[ ++a[0] ] = k; }  
    void re() { reverse(a+1, a+a[0]+1); }          //STL自带的反转字符串的函数      
    void print()                                      
    {  
        printf("%d", a[ a[0] ]);        
        for (int i = a[0]-1;i > 0;--i)  
        printf("%0*d", power, a[i]);      
        printf("\n");  
    }  
} dp[46][46][16],cc;  
bool operator < (const num &p, const num &q)  
{  
    if (p.a[0] < q.a[0]) return true;  
    if (p.a[0] > q.a[0]) return false;  
    for (int i = p.a[0];i > 0;--i)  
    {  
        if (p.a[i] != q.a[i]) return p.a[i] < q.a[i];  
    }  
    return false;  
}     
num operator * (const num &p, const num &q)                    
{  
    num c;  
    c.a[0] = p.a[0]+q.a[0]-1;  
    for (int i = 1;i <= p.a[0];++i)  
    for (int j = 1;j <= q.a[0];++j)  
    {  
        c.a[i+j-1] += p.a[i]*q.a[j];  
        c.a[i+j] += c.a[i+j-1] / base;  
        c.a[i+j-1] %= base;  
    }  
    if (c.a[ c.a[0]+1 ]) ++c.a[0];  
    return c;  
}  
int n,k,cnt;
char fz[MAXL],zh[MAXL];
int main()  
{  
	register int i,j,kk,len,l,sl;
	scanf("%d%d%s",&n,&k,&fz);
	for(i=1;i<=n;i++)
		for(j=1;j<=n;j++)
		{
			cnt=0;memset(zh,0,sizeof zh);
			for(kk=i-1;kk<j;kk++) zh[cnt++]=fz[kk];
			reverse(zh,zh+strlen(zh));
			dp[i][j][0]=num(zh);
            //添加0个乘号即为它本身
		}
	for(l=1;l<=k;l++)
    //要添加的乘号数
		for(len=2;len<=n;len++)
        //按长度枚举,保证长度短的先被枚举
			for(i=1;i<=n-len+1;i++)
			{
            //i为左端点,j为右端点
				j=i+len-1;
				for(sl=0;sl<l;sl++)
				for(kk=i+1;kk<=j;kk++)
				{
						cc=dp[i][kk-1][sl]*dp[kk][j][l-sl-1];
						if(dp[i][j][l]<cc) dp[i][j][l]=cc;//就是上面的方程
				}
			}
	dp[1][n][k].print();
	return 0;
}  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值