http://oi.nks.edu.cn/zh/Problem/Details?cid=2207&tid=B
第一种解法
线性筛log求质因子然后d(n)求约数暴力乘就行了
时间复杂度O(1e7+t*logn*d(n)) 数据弱能过
#include <bits/stdc++.h>
#define int long long
#define re register
using namespace std;
const int maxn = 1e7 + 2;
const int maxm = 1000;
const int mod = 1e9 + 7;
int t;
int n;
int cnt;
int cc;
bool vis[maxn];
int prime[maxn];
int tp[maxn];
int p[maxm];
int r[maxm];
int y[maxm];
inline void eula(int x) {
for(re int i = 2; i < x; ++ i) {
if(!vis[i]) {
prime[++ cnt] = i;
tp[i] = cnt;
}
for(re int j = 1; j <= cnt && i * prime[j] < x; ++ j) {
vis[i * prime[j]] = true;
tp[i * prime[j]] = j;
if(i % prime[j] == 0) break;
}
}
}
inline void fj(int x) {
while(x != 1) {
//cout<<prime[tp[x]]<<endl;
if(prime[tp[x]] != p[cc]) {
p[++ cc] = prime[tp[x]];
}
x /= prime[tp[x]];
++ r[cc];
}
}
inline int ys() {
int m = 0;
int sum = 1;
y[++ m] = 1;
for(re int i = 1; i <= cc; ++ i) {
int tt = m, sm = 1;
for(re int j = 1; j <= r[i]; ++ j) {
sm *= p[i];
sum %= mod;
for(re int k = 1; k <= tt; ++ k) {
y[++ m] = sm * y[k];
sum %= mod;
}
}
}
for(re int i = 1; i <= m; ++ i) {
sum *= y[i];
sum %= mod;
}
return sum;
}
inline int read() {
int sum = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
sum = (sum << 3) + (sum << 1) + (c ^ 48);
c = getchar();
}
return f * sum;
}
signed main() {
t = read();
eula(maxn);
while(t --) {
memset(p, 0, sizeof(p));
memset(r, 0, sizeof(r));
cc = 0;
n = read();
fj(n);
// for(re int i = 1; i <= cc; ++ i) {
// cout<<r[i]<<" "<<p[i]<<endl;
// }
int ans = ys();
printf("%lld\n", ans);
}
return 0;
}
第二种解法
用线性筛推公式做
当prime[j](当前最小质因子)第一次出现
这个数和前面的所有数相乘再算上前面的数
否则
因为最小质因子指数加了一,就会出现所有不包含这个质因子的数乘上这个质因子的指数次方,
再把这些数相乘,还有前面算的
#include <bits/stdc++.h>
#define ll long long
#define re register
using namespace std;
const int maxn = 1e7 + 2;
const int mod = 1e9 + 7;
int cnt;
int t;
int n;
bool vis[maxn];
int prime[maxn];
int r[maxn];
int d[maxn];
int g[maxn];
ll k[maxn];
inline ll qpow(int a, int b) {
ll ans = 1;
ll tp = a;
while(b > 0) {
if(b & 1) {
ans *= tp;
ans %= mod;
}
tp *= tp;
tp %= mod;
b >>= 1;
}
return ans % mod;
}
inline void eula() {
d[1] = 1;
k[1] = 1;
for(re int i = 2; i <= maxn - 2; ++ i) {
if(!vis[i]) {
prime[++ cnt] = i;
r[i] = 1;
d[i] = 2;
k[i] = i;
g[i] = i;
}
for(re int j = 1; j <= cnt && i * prime[j] <= maxn - 2; ++ j) {
vis[i * prime[j]] = true;
if(i % prime[j] == 0) {
r[i * prime[j]] = r[i] + 1;
d[i * prime[j]] = d[i] * (r[i] + 2) / (r[i] + 1);
g[i * prime[j]] = g[i] * prime[j];
k[i * prime[j]] = k[i] * qpow(g[i * prime[j]], d[i / g[i]]) % mod * k[i / g[i]] % mod;
break;
}else {
r[i * prime[j]] = 1;
d[i * prime[j]] = 2 * d[i];
g[i * prime[j]] = prime[j];
k[i * prime[j]] = k[i] * k[i] % mod * qpow(prime[j], d[i]) % mod;
}
}
}
}
inline int read() {
int sum = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
sum = (sum << 3) + (sum << 1) + (c ^ 48);
c = getchar();
}
return f * sum;
}
signed main() {
eula();
t = read();
while(t --) {
scanf("%d", &n);
printf("%lld\n", k[n]);
}
return 0;
}
快速幂加上取模常数有点大,甚至比暴力慢一些
第三种解法
约数是成组出现的
12 = 1 * 12, 2 * 6, 3 * 4
答案为12的三次方,特判一下完全平方数即可
#include <bits/stdc++.h>
#define ll long long
#define re register
using namespace std;
const int maxn = 1e7 + 2;
const int mod = 1e9 + 7;
int cnt;
int t;
int n;
bool vis[maxn];
int prime[maxn];
int r[maxn];
int d[maxn];
inline ll qpow(int a, int b) {
ll ans = 1;
ll tp = a;
while(b > 0) {
if(b & 1) {
ans *= tp;
ans %= mod;
}
tp *= tp;
tp %= mod;
b >>= 1;
}
return ans % mod;
}
inline void eula() {
for(re int i = 2; i <= maxn - 2; ++ i) {
if(!vis[i]) {
prime[++ cnt] = i;
r[i] = 1;
d[i] = 2;
}
for(re int j = 1; j <= cnt && i * prime[j] <= maxn - 2; ++ j) {
vis[i * prime[j]] = true;
if(i % prime[j] == 0) {
r[i * prime[j]] = r[i] + 1;
d[i * prime[j]] = d[i] * (r[i] + 2) / (r[i] + 1);
break;
}else {
r[i * prime[j]] = 1;
d[i * prime[j]] = 2 * d[i];
}
}
}
}
inline int read() {
int sum = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
sum = (sum << 3) + (sum << 1) + (c ^ 48);
c = getchar();
}
return f * sum;
}
signed main() {
eula();
t = read();
while(t --) {
scanf("%d", &n);
ll ans = 0;
if(d[n] & 1) {
ans = qpow(n, d[n] / 2) * (ll)sqrt(n) % mod;
}else {
ans = qpow(n, d[n] / 2);
}
printf("%lld\n", ans);
}
return 0;
}
跑的很快,O(1e7+t * logn)