1.题目描述:点击打开链接
2.解题思路:本题要求找出1~2^64-1之间所有的超级幂。根据题意,不难知道这样的数的幂次一定是一个合数。而最大的幂次肯定不超过64,因此只需要去除4~64之间所有的素数即可,而这些素数可以事先打表。接下来开始枚举底数和幂次。由于幂次最多只有不超过60个,每个幂次对应的底数不超过10^5个,因此时间复杂度可以承受。
但这里还有一个问题:如何知道枚举到哪个幂次就停止枚举呢?很简单,只需要实现从2^64-1开始,计算出以i为底数的最大幂次的边界cnt即可。当cnt<4时即可中断枚举底数。注意:本题应该使用ull类型,同时为了防止重复,把结果存入set中。
3.代码:
#define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<algorithm> #include<string> #include<sstream> #include<set> #include<vector> #include<stack> #include<map> #include<queue> #include<deque> #include<cstdlib> #include<cstdio> #include<cstring> #include<cmath> #include<ctime> #include<functional> using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> P; typedef pair<long long, long long> PL; #define me(s) memset(s,0,sizeof(s)) #define For(i,n) for(int i=0;i<(n);i++) int primes[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61 }; int vis[70]; int main() { //freopen("t.txt", "w", stdout); ull lim = ~0LL >> 1;//最大边界 set<ull>s; for (int i = 0; i < 18; i++) vis[primes[i]] = 1;//标记素数 for (ull i = 2;; i++)//枚举底数 { ull cnt = -1, x = lim; while (x)//计算出最大的指数cnt { x /= i; cnt++; } if (cnt < 4)break; ull b = i; for (ull j = 2; j <= cnt; j++) { b *= i; if (!vis[j])//枚举指数,如果该指数是合数,就放入set s.insert(b); } } s.insert(1);//1是一个特例,最后放入 set<ull>::iterator it; for (it = s.begin(); it != s.end(); it++) cout << *it << '\n'; return 0; }
原文地址:http://blog.csdn.net/u014800748/article/details/45914353