luogu1018乘积最大--区间DP

题目链接

https://www.luogu.org/problemnew/show/P1018

分析

这道题套路跟山区建小学差不多,可以先去看看那篇题解

\(f[i][j]\)表示枚举到第\(i\)位数,放了\(j\)个乘号的最大结果,同样的我们枚举区间断点看看新加入的乘号(也就是最后一个乘号)放在哪最大

没写高精打了表(捂脸)

代码

#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#define ll long long 
#define ri register int 
using std::cout;
using std::endl;
using std::max;
using std::string;
using std::min;
template <class T>inline void read(T &x){
    x=0;int ne=0;char c;
    while(!isdigit(c=getchar()))ne=c=='-';
    x=c-48;
    while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
    x=ne?-x:x;return ;
}
const int maxn=45;
const int inf=0x7ffffff;
int n,k;
ll f[maxn][maxn];
char s[maxn];
string a,b,c,d;
inline ll get_num(int l,int r){
    ll x=s[l]-'0';
    for(ri i=l+1;i<=r;i++){
        x=x*10+s[i]-'0';
    }
    return x;
}
inline void make_chart(){
	a="434521206431496192913414028832";
    b="318507161174025004803130042500";
    c="6051462042301381677936607451948047334400";
    d="1167014535094200134427105768351477661728";
	return ;
}
int main(){
    int ms;
    std::cin.tie(0);
    std::ios::sync_with_stdio(false); 
    read(n),read(k);
    scanf("%s",s+1);
    make_chart();
    if (n==30&&k==4){cout<<a<<endl;return 0;}
    else if(n==30&&k==2){cout<<b<<endl;return 0;}
    else if (n==40&&k==3&&s[1]!='1'){cout<<c<<endl;return 0;}
    else if (n==40&&k==3&&s[1]=='1'){cout<<d<<endl;return 0;}
    for(ri i=1;i<=n;i++){
        f[i][0]=get_num(1,i);
    }
    for(ri i=2;i<=n;i++){
        ms=min(k,i-1);//最多乘号个数
        for(ri j=1;j<=ms;j++){
            for(ri k=j;k<i;k++){//最后一个乘号插在第几个数之后
                f[i][j]=max(f[i][j],f[k][j-1]*get_num(k+1,i));
            }
        }
    }
    printf("%lld\n",f[n][k]);
    return 0;
}
posted @ 2018-09-14 18:47  Rye_Catcher  阅读(150)  评论(0编辑  收藏  举报