【题解】【P1249 最大乘积】
题目大意
将
题解
楼上给了很多贪心的做法,然而并不是那么容易理解。这里给一个非常容易理解然而复杂度很劣的
互不相同这个条件可以改为从
在数学里,对数有一个很好的性质:
假如我们要选出一些数使得它们的乘积最大,就等价于这些数的对数之和最大。
因此题目就很显然了。
然后滚动数组优化一下,就可以
接着我们只需要写一个高精乘低精的乘法就行了。
参考代码
#include<bits/stdc++.h>
#define up(l,r,i) for(int i=l;i<=r;i++)
#define dn(l,r,i) for(int i=l;i>=r;i--)
using namespace std;
typedef long long LL;
const int INF =2147483647;
int qread(){
int w=1,c,ret;
while((c=getchar())> '9'||c< '0')
w=(c=='-'?-1:1); ret=c-'0';
while((c=getchar())>='0'&&c<='9')
ret=ret*10+c-'0';
return ret*w;
}
const int MAXN =1e4+3,MAXL=1e5+3;
int n,C[MAXN],flg[MAXN];double W[MAXN],dp[MAXN];
vector <int> ans;
struct Node{
int dt[MAXL],len; Node():len(0){memset(dt,0,sizeof(dt));}
Node operator *(int t){
Node res; up(1,len,i) res.dt[i]=dt[i]*t;
up(1,len+10,i){
res.dt[i+1]+=res.dt[i]/10,res.dt[i]%=10;
if(res.dt[i]) res.len=i;
}
return res;
}
}val;
int main(){
n=qread(); up(1,n,i) W[i]=log(i);
up(1,n,i) dp[i]=-INF;
up(1,n,i) dn(n,i,j){
if(dp[j-i]+W[i]>dp[j]) dp[j]=dp[j-i]+W[i],flg[j]=j-i;
}
for(int p=n;p;p=flg[p]) ans.push_back(p-flg[p]);
dn(ans.size(),1,i) printf("%d ",ans[i-1]); puts("");
val.len=1,val.dt[1]=1;
up(1,ans.size(),i) val=val*ans[i-1];
dn(val.len,1,i) putchar('0'+val.dt[i]); puts("");
return 0;
}
其他
虽然这个算法跑得没有贪心快,但是应该是比较容易理解的(万一哪天题目改成另外一种选法,这个算法的思想依然适用,即化积为和。)而且这种算法不需要脑子,证明超简单,随手就能写出来
另外,如果运行上述程序,稍微打几个表也能发现规律了。前面几个题解已经讲的很详尽了,这里不再赘述。