题目链接:https://www.luogu.com.cn/problem/P1018
思路:
因为20×20会超longlong,所以开个高精度,然后记录dp[i][j]表示将1~j的数字分为k段的最大值是多少,从前往后更新就好了。
最终输出分为k+1段后的结果即可。
(记第一个作对的绿题)
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct Node
{
int len = 0,nu[120] = {0};
}dp[10][55];
char ss[120];
Node f(int l,int r)
{
Node tp;
tp.len = r - l + 1;
for(int i=r,j=1;j<=tp.len;i--,j++)
{
tp.nu[j] = (ss[i] - '0');
}
return tp;
}
void Pt(Node tp)
{
for(int i=tp.len;i>=1;i--) printf("%d",tp.nu[i]);
printf("\n");
}
Node Max(Node a,Node b)
{
if(a.len > b.len) return a;
else if(a.len < b.len) return b;
for(int i=a.len;i>=1;i--)
if(a.nu[i] > b.nu[i]) return a;
else if(a.nu[i] < b.nu[i]) return b;
return a;
}
Node Mul(Node a,Node b)
{
Node c;
for(int i=1;i<=a.len;i++)
{
for(int j=1;j<=b.len;j++)
c.nu[i+j-1] += a.nu[i]*b.nu[j];
}
c.len = a.len + b.len-1;
for(int i=1;i<=c.len;i++)
{
if(c.nu[i] >= 10)
{
if(i+1>c.len){
c.len++;
}
c.nu[i+1] += c.nu[i]/10;
c.nu[i] %= 10;
}
}
while(c.len>=1 && c.nu[c.len] == 0) c.len--;
if(c.len == 0)
{
c.nu[1] = 0;
c.len = 1;
}
return c;
}
int main(void)
{
int n,k;
scanf("%d%d",&n,&k);
scanf("%s",ss+1);
//Pt(Mul(f(1,2),f(3,4)));
for(int i=1;i<=k+1;i++)
{
for(int j=i;j<=n;j++)
{
if(i == 1) dp[i][j] = f(i,j);
else{
for(int t=i-1;t<j;t++) //注意,这里t从i-1开始,因为上次分为了i-1段
dp[i][j] = Max(dp[i][j],Mul(dp[i-1][t],f(t+1,j)));
}
}
}
Pt(dp[k+1][n]);
return 0;
}