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;
}

 

posted on 2020-10-29 15:33  Aminers  阅读(176)  评论(0编辑  收藏  举报

导航