反素数
反素数的定义:对于任何正整数,其约数个数记为,例如,如果某个正整数满足:对任意的正整
数,都有,那么称为反素数。
从反素数的定义中可以看出两个性质:
(1)一个反素数的所有质因子必然是从2开始的连续若干个质数,因为反素数是保证约数个数为的这个数尽量小
(2)同样的道理,如果,那么必有
其实知不知道反素数这个东西倒是无所谓。关键是理解这两条性质是怎么得出来的。理解了这个,那么相关的题就往这方面想就行了。
这里解释一下这两条性质:定义里的是严格小于,这个很重要,这就决定了一个数如果是反素数,那么它一定是满足条件的最小的数。
那么要找反素数,一定是按着这两条性质来找才能保证是最小的。
例题:
Codeforces#27(div2)E:
http://codeforces.com/problemset/problem/27/E
题意:给一个正整数n,输出有n个因子的最小的数。
就是按那两条思路来dfs。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<map> #include<set> #include<vector> #include<algorithm> #include<stack> #include<queue> using namespace std; #define INF 1000000000 #define eps 1e-8 #define pii pair<int,int> #define LL long long int #define ULL unsigned long long int int prime[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47}; /*素数一直连乘,乘到47就不能再往下乘了,否则就超了unsigned long long int了*/ int n; ULL ans=1000000000000000009; void dfs(int pi,int num,int limit,ULL temp) /*pi表示当前用到第几个素数,num表示当前数的因子个数, limit表示当前用到的这个素数最多能用几次方,temp表示当前数的大小。*/ { if(num>n) return; else if(num==n) { ans=min(ans,temp); return; } else { ULL t=prime[pi]; for(int i=1;i<=limit;i++,t*=prime[pi]) { dfs(pi+1,num*(i+1),i,temp*t); } } } int main() { //freopen("in6.txt","r",stdin); //freopen("out.txt","w",stdout); scanf("%d",&n); dfs(0,1,60,1); printf("%I64d ",ans); return 0; }
这道题和上道题一样的,旧瓶装新酒。我之前过了,今天又写了一遍怎么都得不到正确结果,原来是递归函数传参数时改变了原来的值。以前真没有注意到这个易错点。经验值+1。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<map> #include<set> #include<vector> #include<algorithm> #include<stack> #include<queue> using namespace std; #define INF 1000000000 #define eps 1e-8 #define pii pair<int,int> #define LL long long int #define ULL unsigned long long int LL n,ans,anum; long long prime[16]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47}; /*先用计算器算一下乘到哪个就够了,避免下面不必要的计算。*/ void dfs(LL pi,LL limit,LL num,LL temp) { if(temp>n) return; else { if(num>anum) { anum=num; ans=temp; } else if(num==anum&&temp<ans) { ans=temp; } LL t=(LL)prime[pi]; for(LL i=1; i<=limit; i++,t*=(LL)prime[pi]) { if(temp*t>n)break;// else dfs(pi+1,i,num*(i+1),temp*t); /*这里犯了一个错误,导致一直WA而找不到bug。 我把这句写成了dfs(pi+1,i,num*(i+1),temp*=t); 这个错误非常典型!在递归调用函数时,我要传入temp*t的值, 但是如果这么写,当前函数的这一层的temp也变了!而此时for循环 可能还没有结束,temp的值变了肯定会导致错误。 包括第一个参数就得写成pi+1而不能写成pi++也是一样的道理。*/ /*这使我认识到了一个重要点:注意递归调用函数传递参数时,不要改变原参数的值!!!*/ } } } int main() { //freopen("in7.txt","r",stdin); //freopen("out.txt","w",stdout); while(scanf("%I64d",&n)==1) { ans=1; anum=1; dfs(0,51,1LL,1LL); printf("%I64d ",ans); } //fclose(stdin); //fclose(stdout); return 0; }