HDU3692--least common multiple(数论优化+分组背包);DP--数论

来源:互联网 发布:mysql 修改字段长度 编辑:程序博客网 时间:2024/06/03 18:04
CCPC网络赛开始报名了~ 
欢迎参加——阿里云“智慧航空AI大赛”(报名中...) 

Least common multiple

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 825    Accepted Submission(s): 352


Problem Description
Partychen like to do mathematical problems. One day, when he was doing on a least common multiple(LCM) problem, he suddenly thought of a very interesting question: if given a number of S, and we divided S into some numbers , then what is the largest LCM of these numbers? partychen thought this problems for a long time but with no result, so he turned to you for help!
Since the answer can very big,you should give the answer modulo M.
 

Input
There are many groups of test case.On each test case only two integers S( 0 < S <= 3000) and M( 2<=M<=10000) as mentioned above.
 

Output
Output the largest LCM modulo M of given S.
 

Sample Input
6 23
 

Sample Output
6Hint: you can divied 6 as 1+2+3 and the LCM(1,2,3)=6 is the largest so we output 6%23=6.
 

Source
2009 Multi-University Training Contest 18 - Host by ECNU
 

Recommend
lcy   |   We have carefully selected several similar problems for you:  3089 3090 3095 3094 3093 



题意:给一个数S,并把S分割成若干个数的和的形式,求这若干个数的最小公倍数的最大值对M取余。
思路:当一个数被分割成未知项,我们需要如何考虑,才能使它的最小公倍数尽可能的大呢?如果里面第i项是第j项的约数,那么他们的最小公倍数就会至少减小他们乘积的2倍,这样求出的解一定不是最优解,所以我们需要把S分割成若干个互质的数,S范围是0到3000,我们可以先对3000以内的素数先打表,那么对于每个小于等于S的每个素数最素数的问题已经显而易见了。我们知道不同素数两两互质,不同素数的次方也互质,但是素数与它本身的次方却不互质,相当于给一个容量为S的背包,有小于等于S的范围内有若干个互质的数,这些互质的数被分为K组(每一组第i个元素是这个素数的i次方),每组最多取一个(如果取两个以上就会产生约数),求把这个背包装满的元素的最大的最小公倍数,这不就是分组背包吗?
        还没完,题目要求对M取模,原因就是,我们求最小公倍数时,DP数组中的元素值有可能超long long,我们一般采取随时取模,当这道题是行不通的,如果随时取模可能影响dp[j]=max(dp[j],dp[  j-k*prime[i]  ]*k*prime[i])的结果,所以我们利用log函数单调递增的特性,对这个状态转移方程取log,然后再用不参与状态转移的另一个数组记录没有取log的结果,就可以啦。
 注意:dp数组声明为double类型。


#include<bits/stdc++.h>#define inf -0x3f3f3f3f#define maxn 3005typedef long long ll;bool visit[maxn];int prime[maxn];double dp[maxn];ll ans[maxn];using namespace std;int num;void getprime(){    num=0;    memset(visit,false,sizeof(visit));    prime[0]=1;    for(int i=2;i<=maxn;i++){        if(!visit[i]) prime[++num]=i;         for(int j=1;j<=num&&i*prime[j]<maxn;j++){            visit[i*prime[j]]=true;            if(i%prime[j]==0)                break;         }    }}int main(){    int s,m;    getprime();    while(~scanf("%d%d",&s,&m)){       for(int i=0;i<=s;i++){        ans[i]=1;        dp[i]=0;       }       for(ll i=1;i<num&&prime[i]<=s;i++){         for(ll j=s;j>=prime[i];j--){            for(ll k=prime[i];k<=j;k*=prime[i]){                    if(dp[j-k]+log(k*1.0)>dp[j]){                        dp[j]=dp[j-k]+log(k*1.0);                        ans[j]=ans[j-k]*k%m;                    }            }         }       }       cout<<ans[s]<<endl;    }}


原创粉丝点击