P1463 [POI2001][HAOI2007]反素数

written on 2022-05-22

很早以前就想写这题了,刚好昨天比赛碰见,于是写一下总结。

刚开始没有想到正解,于是敲了打表,骗了80pts。正确的打表方式……见代码吧

#include<bits/stdc++.h>
using namespace std;
int a[100]={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};
/*
int work(int x)
{
	int cnt=0;
	for(int i=1;i<=sqrt(x);i++)
	{
		if(x%i) continue;
		cnt++;
		if(i*i!=x) cnt++;
	}
	return cnt;
}
int F(int x)
{
	if(x<6) return 1;
	if(x<240) return 6;
	if(x<1680) return 60;
	if(x<110880) return 120;
	return 27720;
}*/
int main()
{
	/*
	int mx=0,p=0;
	for(int i=1;i<=2e9;i+=F(i))
	{
		int x=work(i);
		if(x>mx) mx=x,printf("%d,",i),p++;
	}
	printf("num=%d\n",p);*/
	int n;
	scanf("%d",&n);
	int l=0,r=67,ans;
	while(l<=r)
	{
		int mid=l+r>>1;
		if(a[mid]<=n) l=mid+1,ans=mid;
		else r=mid-1;
	}
	printf("%d\n",a[ans]);
}

另外,正解需要涉及一些数学知识,这里引用一篇优质题解(感谢@_wkjzyc)。

正解的关键在于发现一个数因数个数与质因子之间的关系,也就是这篇题解中所写的第三点,原因是质因子的排列组合组成所有因数。用搜索的方法,要处理的数就会大大减少。另外还要发现指数的单调性与质数的连续性,这里题解中都有涉及到,不再赘述。

贴一下自己的低效代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int p[]={2,3,5,7,11,13,17,19,23,29};
vector<ll> v;
int work(int x)
{
	int cnt=0;
	for(int i=1;i<=sqrt(x);i++)
	{
		if(x%i) continue;
		cnt++;
		if(i*i!=x) cnt++;
	}
	return cnt;
}
ll power(int a,int b)
{
	if(!b) return 1;
	ll res=1;
	while(b)
	{
		if(b&1) res=res*a;
		a=a*a;
		b>>=1;
	}
	return res;
}
void dfs(ll now,int id,int mn)
{
	if(now>2e9||id>=10||now<=0) return ;
	v.push_back(now);
	for(int i=1;i<=mn;i++) dfs(now*power(p[id],i),id+1,i);
}
vector<int> g;
int main()
{
	ll p=1;
	dfs(1ll,0,31);
	sort(v.begin(),v.end());
	int mx=0;
	for(int i=0;i<v.size();i++)
	{
		int x=work(v[i]);
		if(x>mx) g.push_back(v[i]),mx=x;
	}
//	for(int i=0;i<g.size();i++) printf("%d ,",g[i]);
	int n;
	scanf("%d",&n);
	int l=0,r=g.size()-1,ans;
	while(l<=r)
	{
		int mid=l+r>>1;
		if(g[mid]<=n) ans=mid,l=mid+1;
		else r=mid-1;
	}
	printf("%d\n",g[ans]);
}

以及自己的高效代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int p[]={2,3,5,7,11,13,17,19,23,29};
ll power(int a,int b)
{
	if(!b) return 1;
	ll res=1;
	while(b)
	{
		if(b&1) res=res*a;
		a=a*a;
		b>>=1;
	}
	return res;
}
int n,mx;
ll ans;
void dfs(ll now,int id,int mn,int cnt)
{
	if(now>n||id>=10||now<=0) return ;
	if(cnt>mx||(cnt==mx&&now<ans)) mx=cnt,ans=now;
	for(int i=1;i<=mn;i++) dfs(now*power(p[id],i),id+1,i,cnt*(i+1));
}
int main()
{
	scanf("%d",&n);
	dfs(1,0,30,1);
	printf("%lld\n",ans);
}
posted @ 2022-07-31 18:32  Freshair_qprt  阅读(34)  评论(0编辑  收藏  举报