HDU 3092 Least common multiple(完全背包+思维)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/fufck/article/details/82432395

题目链接

题目大意:给你一个数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]);
   }	
} 

猜你喜欢

转载自blog.csdn.net/fufck/article/details/82432395