2024/10/19
整数划分
整数划分 今天解决 整数划分(洛谷) 思考如下 暂时没想好状态转移方程应该如何做,用贪心思想也比较简单。 由题目示例数据可得,将n划分为 2a+3b 形式即可得到最大乘积。 (4 + 3 + 3 + 3 = 2 + 2 + 3 + 3 + 3 = 2x2 + 3x3) 通俗来讲就是尽量分为多个2和3相加,并且3尽可能多才能尽可能地大 既然知道3要尽可能多就好
TalexDreamSoul2 min read
Life
整数划分
今天解决 整数划分(洛谷)
思考如下
暂时没想好状态转移方程应该如何做,用贪心思想也比较简单。
由题目示例数据可得,将n划分为 2a+3b 形式即可得到最大乘积。
(4 + 3 + 3 + 3 = 2 + 2 + 3 + 3 + 3 = 2x2 + 3x3)
通俗来讲就是尽量分为多个2和3相加,并且3尽可能多才能尽可能地大
既然知道3要尽可能多就好办了
划分3
第一种情况,恰好对3取余为0
if ( n % 3 == 0 ) {
int b = n / 3;
// 累计相乘即可 3的n次方 做高精度即可
// ...
}
第二种情况,对3取余为1
其实相当于是将一个3换成2+2
即拿出1个3和余下的1凑成两个2
if ( n % 3 == 1 ) {
int a = 2;
int b = (n - 4) / 3 ;
// 同理做高精度
}
第三种情况,对3取余为2
既然取余剩余2,不妨就多一个单独的2
if ( n % 3 == 2 ) {
int a = 1;
int b = (n - 2) / 3;
}
其实总结一下
要求整数划分,且积越大,就如同矩形周长划分求面积最大,那么就是正方形最大,即越平均答案越大。
高精度
既然我们已经知道应该如何划分,接下来就是计算乘积和输出了。
只需要计算a个2和b个3相乘的答案,并且多余100位输出前100位(后面的还是得算,因为需要位数)
需要单独开一个进位数组,题目给的限制是不超过5000位。
// 实际进位可能会超过5000,所以开大一点
int arr[5010];
void multiple(int x) {
int amo = 0;
for ( int i = 1; i <= arr[0] + 1; ++i ) {
arr[i] = arr[i] * x + amo;
amo = arr[i] / 10;
arr[i] %= 10;
}
// 最后判断一下首位是否需要进位
if ( arr[arr[0] + 1 ])
arr[0]++;
}
拼图
大概结构列起来之后,直接拼起来即可,以下是完整代码
#include <bits/stdc++.h>
using namespace std;
// maximum = 31000
int n;
int arr[5010];
void multiple(int x) {
int amo = 0;
for ( int i = 1; i <= arr[0] + 1; ++i ) {
arr[i] = arr[i] * x + amo;
amo = arr[i] / 10;
arr[i] %= 10;
}
if ( arr[arr[0] + 1 ] )
arr[0]++;
}
void solve() {
if ( n % 3 == 0 ) {
for ( int i = 1; i <= n / 3; ++i) {
multiple(3);
}
cout<<arr[0]<<endl;
for( int i = arr[0]; i >= max(arr[0] - 99, 1); --i ) {
cout<<arr[i];
};
}
if(n % 3 == 1){
for( int i = 1; i <= n / 3 - 1; ++i ) {
multiple(3);
}
multiple(4);
cout<<arr[0]<<endl;
for( int i = arr[0]; i >= max(arr[0] - 99, 1); --i ) {
cout<<arr[i];
}
}
if( n % 3 == 2 ) {
for( int i = 1; i <= n / 3; ++i ) {
multiple(3);
}
multiple(2);
cout<<arr[0]<<endl;
for( int i = arr[0]; i >= max(arr[0] - 99, 1); --i ) {
cout<<arr[i];
}
}
}
int main() {
cin>>n;
arr[0] = 1;
arr[1] = 1;
solve();
return 0;
}
总体来说,这道题是一个结论题目。如果刚开始没思路可以先暴力循环,能发现这个结论。重点在高精度。