题目大意:
题目链接:https://www.luogu.org/problemnew/show/P1463
输出到中约数个数最多且尽量小的数。
思路:
如果你很厉害的话可以打出来一个表。
#include<cstdio>
#include <iostream>
using namespace std;
long long a[]={1,2,4,6,12,24,36,48,60,120,180,240,360,720,840,1260,1680,2520,5040,7560,10080,15120,20160,25200,27720,45360,50400,55440,83160,110880,166320,221760,277200,332640,498960,554400,665280,720720,1081080,1441440,2162160,2882880,3603600,4324320,6486480,7207200,8648640,10810800,14414400,17297280,21621600,32432400,36756720,43243200,61261200,73513440,110270160,122522400,147026880,183783600,245044800,294053760,367567200,551350800,698377680,735134400,1102701600,1396755360,2001000000};
int n,ans,i;
int main()
{
scanf("%d",&n);
while (a[i]<n) i++;
printf("%lld\n",a[i-1]);
return 0;
}
正解是,如果你钻研数据范围的话也可以过。
什么是钻研数据范围呢?
首先,约数个数尽量多,那么我们就把这个数拆成。那么由于所以即使所有的,那么最大的也只要到,因为,所以只要就足够了,换句话说,就行了。
那么来证一下。由于(即),所以肯定不会超过。
那么易证才有最优解(具体证法可以参考《算法竞赛进阶指南》),那么的范围就缩小了很多,直接爆搜即可。
代码:
#include <cstdio>
#include <iostream>
#define ll long long
using namespace std;
const ll num[]={0,2,3,5,7,11,13,17,19,23,29};
ll ans,a[14][41],maxn;
int n;
void dfs(int x,ll sum,int k,ll s)
{
if (sum>n) return;
if (s>ans||(s==ans&&maxn>sum))
{
ans=s;
maxn=sum;
}
if (x>10) return;
for (int i=0;i<=k;i++)
if (a[x][i]<=n)
dfs(x+1,sum*a[x][i],i,s*(i+1));
else break;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=10;i++)
{
a[i][0]=1;
ll k=1;
for (int j=1;j<=30&&k<=n;j++)
{
a[i][j]=k*num[i];
k*=num[i];
}
}
dfs(1,1,30,1);
cout<<maxn;
return 0;
}