P1018 [NOIP2000 提高组] 乘积最大 题解

前言

真是一道 DFS 的好题啊,下次别出了。

题目

这个题我使用了记忆化搜索,记录当前搜到的点和分成的段数的乘积最大值,如果我们搜到这个点后发现这个点的记忆化数组比我们当前的乘积大就没必要再搜下去了,如果比我们的乘积小就更新记忆化数组为我们当前的乘积。

然后处理高精度,这里我推荐将高精度写成结构体,重载高精运算符,这样写着要自然一些。

建议压位,如果不压位可能会超时。

什么是压位?就是将整个数当做一个 1 0 k 10^k 10k 进制数, k k k 最好为 4 4 4,再使用特殊的输出方式,这样可以大大减少运算的次数。

AC Code:

#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
int n, k;
string s;
const int base = 10000;
struct hi_pres{
	int len, num[100];
	hi_pres(){
		len = 0;
		memset(num, 0, sizeof(num));
	}
};
const hi_pres base1;
int getlen(hi_pres a) {
	for (int i = 90; i >= 0; i --) {
		if (a.num[i]) return i;
	}
	return 0;
}
hi_pres operator + (const hi_pres a, const hi_pres b) {
	int la = getlen(a), lb = getlen(b);
	hi_pres c;
	for (int i = 1; i <= max(la, lb); i ++) {
		c.num[i] += a.num[i] + b.num[i];
		c.num[i + 1] += c.num[i] / base;
		c.num[i] %= base;
	}
	return c;
}
hi_pres operator * (const hi_pres a, const hi_pres b) {
	int la = getlen(a), lb = getlen(b);
	hi_pres c;
	for (int i = 1; i <= la; i ++) {
		for (int j = 1; j <= lb; j ++) {
			c.num[i + j - 1] += a.num[i] * b.num[j];
			c.num[i + j] += c.num[i + j - 1] / base;
			c.num[i + j - 1] %= base;
		}
	}
	return c;
}
hi_pres max(const hi_pres a, const hi_pres b) {
	int la = getlen(a), lb = getlen(b);
	if (la > lb) return a;
	if (la < lb) return b;
	for (int i = la; i >= 1; i --) {
		if (a.num[i] > b.num[i]) return a;
		if (a.num[i] < b.num[i]) return b;
	}
	return a;
}
hi_pres to_hi_pres(long long a) {
	hi_pres c;
	int i = 1;
	while (a > 0) {
		c.num[i] = a % base;
		a -= a % base;
		a /= base;
		i ++;
	}
	return c;
}
hi_pres getnum(int l, int r) {
	hi_pres ret;
	for (int i = l; i <= r; i ++) {
		ret = ret * to_hi_pres(10ll);
		ret = ret + to_hi_pres(s[i] - '0');
	}
	return ret;
}
void print(hi_pres a) {
	int la = getlen(a);
	cout << a.num[la];
	for (int i = la - 1; i >= 1; i --) {
		int x = a.num[i];
		if (x == 0) cout << "0000";
		else if (x < 10) cout << "000" << x;
		else if (x < 100) cout << "00" << x;
		else if (x < 1000) cout << "0" << x;
		else cout << x;
	}
}
bool operator < (hi_pres a, hi_pres b) {
	int la = getlen(a), lb = getlen(b);
	if (la > lb) return 0;
	for (int i = la; i >= 1; i --) {
		if (a.num[i] > b.num[i]) return 0;
		if (a.num[i] < b.num[i]) return 1;
	}
	return 0;
}
hi_pres ans;
hi_pres mem[100][10];
void dfs(int n1, int k1, hi_pres num) {
	if (n1 == n) {
		if (k1 == k + 1) {
			ans = max(ans, num);
		}
		return ;
	}
	if (k1 > k + 1) return ;
	if (num < mem[n1][k1]) return ;
	else mem[n1][k1] = num;
	for (int i = n1; i < n; i ++) {
		dfs(i + 1, k1 + 1, num * getnum(n1, i));
	}
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> k >> s;
	dfs(0, 0, to_hi_pres(1));
	print(ans);
	return 0;
}
  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值