cf1225D Power Products cf1471D. Strange Definition

传送门1
传送门2

这两道题特别的像啊,都是对于一个数,去找另一个数,可以说题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();
}
posted @ 2021-01-12 20:42  Emcikem  阅读(113)  评论(0编辑  收藏  举报