乘积最大

好不容易写出来,int改long long又改高精才改对的。

先上题目——

洛谷P1018 [NOIP2000 提高组] 乘积最大

题目描述

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

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

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

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

  1. 3×12=36
  2. 31×2=62

这时,符合题目要求的结果是: 31×2=62

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

输入格式

程序的输入共有两行:

第一行共有 2 个自然数 N,K(6N40,1K6)

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

输出格式

结果显示在屏幕上,相对于输入,应输出所求得的最大乘积(一个自然数)。

输入输出样例

输入 #1
4  2
1231
输出 #1
62

说明/提示

NOIp2000提高组第二题

谈谈思路——

既然说是分成k+1个部分相乘,那么我就开一个数组存着k+1个部分,这样就是一个二维dp,第几个数在第几个部分,判断两种情况,在这个数后放乘号,下个数进入下个部分,或不在这个数后放乘号,下个数依然在这个部分,int和long long都很简单,主要是高精比较难实现。

我用的方法是用void定义dp函数,其中有一个参数是数组,通过递归对数组进行操作实现高精。

#include<iostream>
#include<cstring>
using namespace std;
int n,k;
string s;
int a[200];
long long f[200][10];
bool bj(int x[200],int y[200]){
    if(x[0]>y[0])return true;
    if(x[0]==y[0]){
        for(int j=x[0];j>=1;j--){
            if(x[j]>y[j])return true;
            if(x[j]<y[j])return false;
        }
    }
    return false;
}
void dp(long long qj[10][200],int ans[200],int i,int cnt){
    if(i==n&&cnt<k+1){
        ans[0]=1;
        ans[1]=0;
        return ;
    }
    for(int j=qj[cnt][0];j>=1;j--){
        qj[cnt][j+1]=qj[cnt][j];
    }
    qj[cnt][0]++;
    qj[cnt][1]=a[i];
    if(i==n){
        for(int j=0;j<=qj[cnt][0];j++){
            ans[j]=qj[cnt][j];
        }
    } 
    else{
        dp(qj,ans,i+1,cnt);
        if(cnt<k+1){
            int ans1[200],ans2[200];
            for(int j=0;j<=199;j++){
                ans1[j]=0;
                ans2[j]=0;
            }
            dp(qj,ans1,i+1,cnt+1);
            for(int j=1;j<=ans1[0];j++){
                for(int l=1;l<=qj[cnt][0];l++){
                    ans2[j+l-1]+=ans1[j]*qj[cnt][l];
                }
            }
            ans2[0]=ans1[0]+qj[cnt][0]-1;
            for(int j=1;j<=ans2[0];j++){
                ans2[j+1]+=ans2[j]/10;
                ans2[j]%=10;
            }
            if(ans2[ans2[0]+1]>0){
                ans2[0]++;
            }
            while(ans2[ans2[0]]==0){
                ans2[0]--;
            }
            if(bj(ans2,ans)){
                for(int j=0;j<=ans2[0];j++){
                    ans[j]=ans2[j];
                }
            }
        }
    }
    for(int j=2;j<=qj[cnt][0];j++){
        qj[cnt][j-1]=qj[cnt][j];
    }
    qj[cnt][qj[cnt][0]]=0;
    qj[cnt][0]--;
    return ;
}
int main(){
    cin>>n>>k;
    cin>>s;
    for(int i=1;i<=n;i++){
        a[i]=s[i-1]-'0';
    }
    long long qj[10][200];
    for(int i=1;i<=7;i++){
        for(int j=1;j<=199;j++){
            qj[i][j]=0;
        }
    }
    int ans[200];
    dp(qj,ans,1,1);
    for(int i=ans[0];i>=1;i--){
        cout<<ans[i];
    }
    return 0;
}

感谢一位大佬,我从他那里学到一种方法,比我这个好,就是定义一个结构体node,用node定义dp函数,使得dp函数的返回值是类似于数组的,以此实现高精。

#include<iostream>
#include<cstring>
using namespace std;
int n,k;
string s;
int a[50];
struct node{
    int gao[200];
};
node f[50][10];
bool bj(node x,node y){
    if(x.gao[0]>y.gao[0])return true;
    if(x.gao[0]==y.gao[0]){
        for(int j=x.gao[0];j>=1;j--){
            if(x.gao[j]>y.gao[j])return true;
            if(x.gao[j]<y.gao[j])return false;
        }
    }
    return false;
}
node dp(node qj[10],int i,int cnt){
    if(i==n&&cnt!=k+1){
        f[i][cnt].gao[0]=1;
        f[i][cnt].gao[1]=0;
        return f[i][cnt];
    } 
    for(int j=qj[cnt].gao[0];j>=1;j--){
        qj[cnt].gao[j+1]=qj[cnt].gao[j];
    }
    qj[cnt].gao[1]=a[i];
    qj[cnt].gao[0]++;
    if(i==n) f[i][cnt]=qj[cnt];
    else{
        f[i][cnt]=dp(qj,i+1,cnt);
        if(cnt<k+1){
            node t=dp(qj,i+1,cnt+1);
            node ans;
            for(int j=0;j<=199;j++){
                ans.gao[j]=0;
            }
            for(int j=1;j<=t.gao[0];j++){
                for(int l=1;l<=qj[cnt].gao[0];l++){
                    ans.gao[j+l-1]+=t.gao[j]*qj[cnt].gao[l];
                }
            }
            ans.gao[0]=t.gao[0]+qj[cnt].gao[0]-1;
            for(int j=1;j<=ans.gao[0];j++){
                ans.gao[j+1]+=ans.gao[j]/10;
                ans.gao[j]%=10;
            }
            if(ans.gao[ans.gao[0]+1]>0){
                ans.gao[0]++;
            }
            while(ans.gao[ans.gao[0]]==0){
                ans.gao[0]--;
            }
            if(bj(ans,f[i][cnt])){
                f[i][cnt]=ans;
            }
        }
    } 
    for(int j=2;j<=qj[cnt].gao[0];j++){
        qj[cnt].gao[j-1]=qj[cnt].gao[j];
    }
    qj[cnt].gao[qj[cnt].gao[0]]=0;
    qj[cnt].gao[0]--;
    return f[i][cnt];
}
int main(){
    cin>>n>>k;
    cin>>s;
    for(int i=1;i<=n;i++){
        a[i]=s[i-1]-'0';
    }
    node qj[10];
    for(int i=1;i<=7;i++){
        for(int j=0;j<=199;j++){
            qj[i].gao[j]=0;
        }
    }
    node t=dp(qj,1,1);
    for(int i=t.gao[0];i>=1;i--){
        cout<<t.gao[i];
    }
    return 0;
}

 因为代码里的高精使得DP的思路看的不是那么清楚,所以我就发一下非高精代码:

#include<iostream>
#include<cstring>
using namespace std;
int n,k;
string s;
int a[50];
long long f[50][10];
long long dp(long long qj[10],int i,int cnt){
    if(i==n&&cnt!=k+1) return 0;
    qj[cnt]*=10;
    qj[cnt]+=a[i];
    if(i==n) f[i][cnt]=qj[cnt];
    else if(cnt==k+1) f[i][cnt]=dp(qj,i+1,cnt);
    else f[i][cnt]=max(dp(qj,i+1,cnt),qj[cnt]*dp(qj,i+1,cnt+1));
    qj[cnt]/=10;
    return f[i][cnt];
}
int main(){
    cin>>n>>k;
    cin>>s;
    for(int i=1;i<=n;i++){
        a[i]=s[i-1]-'0';
    }
    long long qj[10];
    for(int i=1;i<=7;i++){
        qj[i]=0;
    }
    cout<<dp(qj,1,1);
    return 0;
}

 2022.3.18

今天又想到一个新思路:

二维数组f[i,j]表示数字串1—i的部分中有j个乘号,且保证i和i+1间是一个乘号,那么我们就需要枚举前一个乘号的位置,找到f[k][i-1]*(k+1到i这段数字串)的最小值。

下面就放一下非高精的代码:

#include<iostream>
using namespace std;
int n,k;
int a[50];
void read(){
    char b=getchar();
    while(b<'0'||b>'9'){
        b=getchar();
    }
    int cnt=1;
    a[cnt]=b-'0';
    while(cnt<=n){
        b=getchar();
        a[++cnt]=b-'0';
    }
}
int f[50][10];
int wucheng(int i,int j){
    int cnt=0;
    for(int l=i;l<=j;l++){
        cnt*=10;
        cnt+=a[l];
    }
    return cnt;
}
int main(){
    cin>>n>>k;
    read();
    for(int i=1;i<=n;i++){
        f[i][0]=f[i-1][0]*10+a[i];
    }
    for(int i=2;i<=n;i++){
        for(int j=1;j<=i-1&&j<=k;j++){
            for(int l=j;l<i;l++){
                f[i][j]=max(f[i][j],f[l][j-1]*wucheng(l+1,i));
            }
        }
    }
    cout<<f[n][k];
    return 0;
}

 

posted @ 2022-02-20 16:44  zzzzzz2  阅读(84)  评论(0)    收藏  举报