题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=3092
Least common multiple
Memory Limit: 65536/65536 K (Java/Others)
样例输出
6
题意
给你一个n,求把n拆成若干个数的和,要求这些数的最小公倍数最大。最后输出%M.
题解
由于最大公倍数会爆,无法直接维护,所以我们可以通过取对数的方式,得到大小,确定转移方向,然后利用这个去维护最优解。
这道题需要用到两个贪心策略:
1、只选质数(或质数的幂)(22*3=12,还不如22+3=7。)
2、每个质数只选一个(如果你拆出39=3+9+27,明显,只有27是有用的。。)然后就可以转换成01背包求解了(贪心策略2决定了这是01背包!不是完全背包)
代码
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#include<sstream>
using namespace std;
#define X first
#define Y second
#define mkp make_pair
#define lson (o<<1)
#define rson ((o<<1)|1)
#define mid (l+(r-l)/2)
#define sz() size()
#define pb(v) push_back(v)
#define all(o) (o).begin(),(o).end()
#define clr(a,v) memset(a,v,sizeof(a))
#define bug(a) cout<<#a<<" = "<<a<<endl
#define rep(i,a,b) for(int i=a;i<(b);i++)
#define scf scanf
#define prf printf
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<pair<int,int> > VPII;
const int INF=0x3f3f3f3f;
const LL INFL=0x3f3f3f3f3f3f3f3fLL;
const double eps=1e-8;
const double PI = acos(-1.0);
//start----------------------------------------------------------------------
const int maxn=3333;
double dp[maxn];
LL ans[maxn];
bool pri[maxn];
VI arr;
void pre() {
clr(pri,0);
for(int i=2; i*i<maxn; i++) {
if(!pri[i]) {
for(int j=i*i; j<maxn; j+=i) {
pri[j]=true;
}
}
}
for(int i=2; i<maxn; i++) if(!pri[i]) arr.pb(i);
}
int main() {
pre();
int S,M;
while(scf("%d%d",&S,&M)==2) {
clr(dp,0);
double Ma=-1;
LL last=1;
for(int i=0; i<=S; i++) ans[i]=1;
//01背包
for(int i=0; arr[i]<=S; i++) {
for(int j=S; j>=arr[i]; j--) {
for(int k=arr[i]; k<=j; k*=arr[i]) {
if(dp[j]<dp[j-k]+log10(k)) {
dp[j]=dp[j-k]+log10(k);
ans[j]=ans[j-k]*k%M;
}
}
if(Ma<dp[j]+eps) {
Ma=dp[j];
last=ans[j];
}
}
}
prf("%I64d
",last);
}
return 0;
}
//end-----------------------------------------------------------------------