cf1225D Power Products cf1471D. Strange Definition
这两道题特别的像啊,都是对于一个数,去找另一个数,可以说题2是修改于题1的。
gcd那题是把含偶数次的都给消掉,最后用map去存,而\(x^k\)这题就是把质因子的幂是\(k\)次的都消掉,最后用map去存,然后根据k去匹配。
\(x^k\)要注意的一点是,\(k\)大于34时,就不需要去用这种方法了,只需要找到1的个数,然后去两两匹配,因为此时\(x^k\)非常大,大于\(1e10\)了,而且这种方法可能爆ll把,所以特判一下就行了
ll a[N];
int n, k;
std::map<int, int> mp;
void divi(int n){
ll ans = 1;
for(int i = 2; i * i <= n; i++) {
if(n % i == 0) {
int tot = 0;
while(n % i == 0) n /= i, tot++;
tot %= k;
for(int j = 1; j <= tot; j++) ans *= i;
}
}
if(n > 1) ans *= n;
mp[ans]++;
}
ll get(ll n){
ll ans = 1;
for(int i = 2; i * i <= n; i++) {
if(n % i == 0) {
int tot = 0;
while(n % i == 0) n /= i, tot++;
for(int j = 1; j <= k - tot; j++) ans *= i;
}
}
if(n > 1) for(int j = 1; j <= k - 1; j++) ans *= n;
return ans;
}
void cal(){
for(int i = 1; i <= n; i++) divi(a[i]);
ll ans = 0;
for(auto xx : mp) {
ll now = get(xx.first);
if(now == xx.first) ans += 1ll * xx.second * (xx.second - 1);
else {
if(mp.count(now)) ans += 1ll * xx.second * mp[now];
}
}
printf("%lld\n", ans / 2);
}
void solve(int kase){
scanf("%d%d", &n, &k);
for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);
if(k >= 34) {
ll tot = 0;
for(int i = 1; i <= n; i++) tot += a[i] == 1;
printf("%lld\n", tot * (tot - 1) / 2);return;
}
cal();
}
I‘m Stein, welcome to my blog