zoukankan      html  css  js  c++  java
  • 转化01背包+用对数存值

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3092

    给你一个数n,它可以被切割成许多整数的和,比如6=1+2+3,这些数字在一起有一个最小公倍数LCM。现在要我们求出切割成整数可以的到的最大的最小公倍数。

    要想切割之后得到最大的最小公倍数,那么切割的数字之间最好就是两两互质,每两个数字的最小公倍数就是a*b/gcd(a,b),当a,b互质的时候,gcd(a,b)==1。所以我们就可以把1到3000里面的素数筛出来,然后看n里面可以包含哪些素数,比如9=2+2+5,所以最大的值就是2^2*5=20。对于一个素数我们拿的是它小于等于容量时的最大次方数。于是就可以转化为01背包。

    但是我wa了好多次,这里有个注意的地方就是答案是最大LCM对m取模的值,不可以边计算边取模,这样会导致答案错误,但是用基本数据类型会溢出啊,但是在再一次看别人博客之后不得不说人的脑洞是真的大。我们可以用dp数组来储存LCM的对数,就是log(LCM),然后用另一个数组ans来存储LCM对m取模的值,这样就可以得到正确的结果。

    公式就是log(a*b)=log(a)+log(b),log(a^c)=clog(a)。

    具体可以看代码:

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<map>
    #include<stack>
    #include<cmath>
    #include<vector>
    #include<set>
    #include<cstdio>
    #include<string>
    #include<deque> 
    using namespace std;
    typedef long long LL;
    #define eps 1e-8
    #define INF 0x3f3f3f3f
    #define maxn 3005
    /*struct point{
        int u,w;
    };
    bool operator <(const point &s1,const point &s2)
    {
        if(s1.w!=s2.w)
        return s1.w>s2.w;
        else
        return s1.u>s2.u;
    }*/
    double dp[maxn]; 
    int n,m,k,t,cnt;
    int prime[maxn];
    bool vis[maxn];
    int ans[maxn];
    void init()
    {
        cnt=0;
        memset(vis,false,sizeof(vis));
        for(int i=2;i<maxn;i++){
            if(!vis[i])
            {
                prime[++cnt]=i;
                for(int j=2*i;j<=maxn;j+=i){
                    vis[j]=true;
                }
            }
        }    
    }
    int main()
    {
        init();
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            memset(dp,0,sizeof(dp));
            fill(ans,ans+maxn-1,1);
            for(int i=1;i<=cnt&&prime[i]<=n;i++){//枚举素数 
                double lo=log10(prime[i]*1.0);//求素数的对数 
                for(int j=n;j>=prime[i];j--){//对于素数的倍数,只能拿一次,所以逆序 
                    for(int num=1,k=prime[i];k<=j;k*=prime[i],num++){// log(a*b)=log(a)+log(b) log(a^c)=clog(a) 
                        if(dp[j]<dp[j-k]+lo*num)
                        {
                            dp[j]=dp[j-k]+lo*num;//dp存最大LCM的对数 
                            ans[j]=(ans[j-k]*k)%m;//ans存最大LCM对m取模的值 
                        }
                    }
                }
            }
            printf("%d
    ",ans[n]);
        }
        return 0;
    }
  • 相关阅读:
    logback-spring.xml配置文件详解
    SpringBoot-Controller接收参数的几种常用方式
    spring boot配置定时任务设置
    SpringCloud 配置文件 application.yml和 bootstrap.yml区别
    ajax/get请求
    ajax封装2
    ajax封装1
    楼层特效
    旋转动画
    联动动画
  • 原文地址:https://www.cnblogs.com/6262369sss/p/9925507.html
Copyright © 2011-2022 走看看