2020 CCPC 威海站 L Clock Master (求n分成若干个数的最大公倍数) 分组背包
题目:https://pintia.cn/problem-sets/1320264931452243968/problems/1320265081436360715
给定一个数n ( 1 ≤ n ≤ 30000 ) ,令n = a 1 + a 2 + a 3 + . . . . 求l c m ( a 1 , a 2 , a 3 , . . . . . ) 的最大值。
思路:
要求lcm最大,因为任意合数可以分成质因数的积,所以lcm可以写成若干素数和他的整数次幂的积,
也就是选素数或他的整数次幂相乘肯定是最优的。
因为如果含有素数x,同时含有x^k,那么x相当于浪费了,也就是素数x和他的整数次幂不能同时选。
把每个素数和他的整数次幂分成一组,在一组的不能同时选,就是实打实的分组背包了。
对数ln a*b =ln a +ln b,所以原来的dp方程就可以写成+法,
dp[j]=max(dp[j],d[j-cost]*value) --->>>> (取log后) dp[j]=max(dp[j],d[j-cost]+log(value)) ,dp[j]就表示容量为j的最大价值求log之后的值。
#include<bits/stdc++.h> #include<ext/rope> //#include<hash_map> #define sd(x) scanf("%d",&x) #define lsd(x) scanf("%lld",&x) #define ms(x,y) memset(x,y,sizeof x) #define fu(i,a,b) for(int i=a;i<=b;i++) #define fd(i,a,b) for(int i=a;i>=b;i--) #define all(a) a.begin(),a.end() using namespace std; using namespace __gnu_cxx; typedef long long ll; typedef unsigned long long ull; typedef long double ld; const int maxn=3e4+91; const int mod=1e9+7; const int INF=1e9+7; const double pi=acos(-1); int prm[maxn],sz; bool isp[maxn]; double dp[maxn],loog[maxn]; int main() { std::ios::sync_with_stdio(false); std::cin.tie(0);//cout和printf不要不要不要连用!! fu(i,0,maxn-1) { isp[i]=1;dp[i]=0; loog[i]=log(i); } isp[1]=0; for(int i=2;i<maxn;i++) { if(isp[i]) prm[++sz]=i; for(int j=1;j<=sz&&i*prm[j]<maxn;j++) { isp[i*prm[j]]=0; if(i%prm[j]==0) break; } } fu(i,1,sz)//每个素数和它的整数次幂为一组 { fd(j,maxn-1,prm[i]) { for(ll k=prm[i];k<=j;k*=prm[i]) dp[j]=max(dp[j],dp[j-k]+loog[k]); } } int t;cin>>t; while(t--) { int n;cin>>n; printf("%.9f\n",dp[n]); } return 0; }