题意:如果一个数可以写成两个不同的数的幂,而且这个幂都不为1,那么我们称这个数为超级数。比如64=2^6=4^3。现在要求输出所有1~64的超级数。
题解:经分析,所有ai^pi&pi为大于等于4的合数都为超级数,比如pi=6可以分解为2,3,那么ai^6=(ai^2)^3。
注意1也满足条件。另外,我们不需要提前筛选ai,暴力2~1e5即可。时间复杂度不超过1e5*64。
补充:注意判断a*i是否超过2^64-1是最重要的步骤
1.unsigned long long:
- 为什么用这个,因为它可以表示64位正数,即最大表示到2^64-1。而普通的long long有一位符号位,表示范围为-(2^63-1)~(2^63-1)
- 使用unsigned long long表示的数会对2^64自动取余
- 输入输出都要使用“%llu”,不然是会出错的
- 我们这里判断a*i是否超出2^64:判断((a*i)/i!=a)?。注意不能用(a*i<a),因为取余之后不一定<a
2.ceil
- ceil:向上取整
- round:四舍五入
- floor:向下取整
- 。。注意要向上取整然后<limit,因为如果不向上取整而只是<=limit有的数它就可能刚好等于2^64(只有这一个例外,也可以最后删除)。
- 唉,你会不会做是一回事。赛场上是否能保持好状态,不自闭的debug掉所有坑是另外一回事
代码:
#include <bits/stdc++.h>
// #define unsigned int long long
#define int unsigned long long
#define read(x) scanf("%llu", &x)
#define print(a, c) printf("%llu%c", a, c)
#define dbg(x) cout << #x << "===" << x << endl
#define pb push_back
using namespace std;
const int N = 1e6 + 10;
// const int INF = 18446744073709551615; // 2**64-1
int n;
int vis[N], sum[N], p[N];
int i, j;
void solve(int n) {
//埃氏筛
for (i = 2; i <= n; i++) {
if (vis[i]) continue;
p[++p[0]] = i;
for (j = i * 2; j <= n; j += i) vis[j] = 1; // vis[i]=1为非素数
}
// for (i = 1; i <= 20; i++) cout << i << " " << vis[i] << endl;
//筛选不能写成a^p&p>1的数。然后**4,**6,**这些合数都满足条件。
// update,发现没必要筛选一下(永远记住,能暴力一定暴力)
set<int> ans;
for (i = 2; i <= n; i++) {
int a = i;
int limit = (int)ceil(64.0 * log(2.0) / log(1.0 * i));
// if (i <= 10) cout << i << " " << limit << endl;
limit = 100; //不使用上面代码的话
for (j = 1; j < limit; j++) {
if (vis[j]) ans.insert(a);
if ((a * i) / i != a) break; //判断是否大于2**64
a *= i;
}
}
ans.insert(1);
// dbg(ans.size());
for (auto i : ans) print(i, '\n');
}
signed main() {
solve(N - 1);
return 0;
}