ADV-205 拿糖果
问题描述
妈妈给小B买了N块糖!但是她不允许小B直接吃掉。
假设当前有M块糖,小B每次可以拿P块糖,其中P是M的一个不大于根号下M的质因数。这时,妈妈就会在小B拿了P块糖以后再从糖堆里拿走P块糖。然后小B就可以接着拿糖。
现在小B希望知道最多可以拿多少糖。
输入格式
一个整数N
输出格式
最多可以拿多少糖
样例输入
15
样例输出
6
数据规模和约定
N <= 100000
[思路]:
动态规划的思想,设已经拿了n块糖,则最终最多可以拿的糖取决于从剩下的M块糖里,最多可以拿多少糖,则有
solve(M,n)=n+MAX(M)
而MAX(M)=max{solve((M-2*P1)+P1),solve((M-2*P2)+P2),solve((M-2*P3)+P3)….}
所以有solve(M,n)=n+max{solve((M-2*P1)+P1),solve((M-2*P2)+P2),solve((M-2*P3)+P3)….}
求MAX(M)的过程可以在循环中做,最后将MAX(M)的保存在数组里,优化递归,减少运算。
创建一个质数数组表 减少运算量
代码:
import java.util.Scanner;
public class Main
{
private static final int MAX=100000;
private static int[] prime=new int[10000];
private static int[] max=new int[MAX];
private static int pSize=0;
public static void creatPrime(int n)
{
prime[pSize++]=2;
for(int i=3;i<Math.sqrt(n);i++)
{
boolean flag=true;
for(int j=2;j<=Math.sqrt(i)+1;j++)
{
if (i%j==0)
{
flag=false;
break;
}
}
if(flag)
prime[pSize++]=i;
}
}
public static int solve(int m,int n)
{
if(max[m]>=0)
return max[m]+n;
int t=0,MAX=0;
for(int i=0;i<pSize;i++)
{
if(prime[i]>Math.sqrt(m))
break;
if( m%prime[i]==0)
{
t=solve(m-2*prime[i],prime[i]);
if(t>MAX)
MAX=t;
}
}
max[m]=MAX;
return MAX+n;
}
public static void main(String[] args)
{
Scanner cin=new Scanner(System.in);
int n=cin.nextInt();
//初始化max数组
for(int i=0;i<max.length;i++)
max[i]=-1;
max[0]=0;max[1]=0;max[2]=0;max[3]=0;
//生成质数表
creatPrime(n);
System.out.println(solve(n, 0));
}
}