題解:乘積最大
阿新 • • 發佈:2021-06-10
目錄
題目
題目描述
今年是國際數學聯盟確定的“ 2000 ――世界數學年”,又恰逢我國著名數學家華羅庚先生誕辰 90 週年。在華羅庚先生的家鄉江蘇金壇,組織了一場別開生面的數學智力競賽的活動,你的一個好朋友 XZ 也有幸得以參加。活動中,主持人給所有參加活動的選手出了這樣一道題目:
設有一個長度為N的數字串,要求選手使用K個乘號將它分成K+1個部分,找出一種分法,使得這K+1個部分的乘積能夠為最大。
同時,為了幫助選手能夠正確理解題意,主持人還舉了如下的一個例子:
有一個數字串:312, 當 N=3,K=1時會有以下兩種分法:
3×12=36
31×2=62
這時,符合題目要求的結果是: 31×2=62
現在,請你幫助你的好朋友 XZ 設計一個程式,求得正確的答案。
輸入格式
程式的輸入共有兩行:
第一行共有2個自然數 N,K(6≤N≤40,1≤K≤6)
第二行是一個長度為N的數字串。
輸出格式
結果顯示在螢幕上,相對於輸入,應輸出所求得的最大乘積(一個自然數)。
輸入輸出樣例
輸入
4 2
1231
輸出
62
解析
記憶化搜尋,dfs(x,y),x表示第一個乘號出現的位置,y表示還剩多少個乘號。
注意幾個地方
1、計算
long long sum(long long x,long long y) { long long ans = 0; for(int i = x; i <= y; i++) { ans = ans * 10; ans = ans + a[i]; } return ans; }
這個用於計算分出來的段組成的數的值,注意一定要先乘十再累加
2、狀態轉移方程
for(int i = x + 1; i <= N; i++) {
ans = max(ans,dfs(i,y - 1) * sum(x,i - 1));
}
列舉乘號位置,後面繼續搜,前面算數
3、邊界條件
if(dp[x][y]) return dp[x][y];//已經搜過了
if(N - x < y) return 0;//乘號比數多
if(y == 0) return sum(x,N);//乘號用完了
4、高精度
正常來說,這道題需要使用高精,但是重在思路,所以我並沒有花時間去寫。。
程式碼
#include<bits/stdc++.h>
using namespace std;
int N,K;
long long a[10001];
long long dp[101][1001];
long long sum(long long x,long long y) {
long long ans = 0;
for(int i = x; i <= y; i++) {
ans = ans * 10;
ans = ans + a[i];
}
return ans;
}
long long dfs(int x,int y) {
long long ans = 0;
if(dp[x][y]) return dp[x][y];
if(N - x < y) return 0;
if(y == 0) return sum(x,N);
for(int i = x + 1; i <= N; i++) {
ans = max(ans,dfs(i,y - 1) * sum(x,i - 1));
}
return dp[x][y] = ans;
}
int main() {
scanf("%d %d" ,&N,&K);
for(int i = 1; i <= N; i++) {
scanf("%1lld" ,&a[i]);
}
printf("%lld" ,dfs(1,K));
return 0;
}