HDU 3092 Least common multiple(完全背包+思维)
题目链接
题目大意:给你一个数n,你要将它分成若干数字的和,使其的lcm最大,并且对p取模
思路:有一个很显然的性质:分成的若干个数字的必定互质。之后就是完全背包问题了。F[I]表示和为I的得到的最大lcm,F[I]=max(F[I-prime[j]*k]*k*prime[j])
因为F[I]的值可能超过long long范围,我们就对其取一个log,记为数组DP【】
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<string>
#include<map>
#include<queue>
#include<vector>
#include<stack>
#define ll long long
#define maxn 4001000
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define rep(i,a,b) for(int i=a;i<=b;i++)
const ll P=1e9+7;
using namespace std;
ll n,p,ans[3010];
double dp[3010];
int flag[3010],prime[3010],l=0;
void isprime(int n)
{
prime[0]=0;
for(int i=2;i<=n;i++)
{
if(!flag[i]) prime[++l]=i;
for(int j=1;j<=l;j++)
{
if(1ll*prime[j]*i>n) break;
flag[prime[j]*i]=1;
if(i%prime[j]==0) break;
}
}
}
void init()
{
memset(dp,0,sizeof(dp));
for(int i=0;i<=n;i++) ans[i]=1;
}
int main()
{
isprime(3000);
while(scanf("%lld%lld",&n,&p)!=EOF)
{
init();
for(int i=1;i<=l&&prime[i]<=n;i++)
{
double temp=log(prime[i]*1.0);
//printf("%.4lf %d\n",temp,prime[i]);
for(int j=n;j>=prime[i];j--)
{
for(int k=prime[i],q=1;k<=j;k*=prime[i],q++)
if(dp[j-k]+temp*q>dp[j])
{
dp[j]=dp[j-k]+temp*q;
ans[j]=ans[j-k]*k%p;
//printf("%.2lf %d j=%d\n",dp[j],ans[j],j);
}
}
}
printf("%lld\n",ans[n]);
}
}
风在前,无惧!