2020/4/21每日一练

2020/4/21

1.质因数分解 数学题

传送门
题意就是给出一个长度为n<=1e5的序列和一个k范围[2,100],元素范围[1,1e5]。求aiaj=pow(x,k) ,x是任意的。
很容易想到用除过去map找,于是我就先预处理出每个数需要的最小数num,比如k=3时,2所需要的num就是4,因为2
4=8,num[12]是18因为12*18==pow(6,3)。这里我是用质因数分解和快速幂做的。然后x就会是num[aj]*pow(枚举的数,k),因为是次幂所以枚举不会很多,在logn的范围。
复杂度在nloglog左右?
跑了1.7s,还是挺悬的
搜了下其他人的解法,不用用到快速幂,质因数分解也很快。
大概就是质因数次方k模一下k,然后map.find(k-次方)
跑了一下只用了90+ms
别人家的解法

#include 
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int maxn = 1e5 + 5;
const ll inf = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
#define all(x) x.begin(), x.end()
int prime[maxn], vis[maxn];
ll num[maxn];
int n, k;
ll ksm(ll a, ll n) {
    ll ans = 1;
    while (n) {
        if (n & 1) {
            if (log10(a) + log10(ans) > 10) return -1;
            ans = ans * a;
        }
        if (log10(a) > 5) return -1;
        a = a * a;
        n >>= 1;
    }
    return ans;
}
void init() {
    num[1] = 1;
    for (int i = 2; i < maxn; i++) {
        num[i] = 1;
        if (!vis[i]) prime[++prime[0]] = i;
        for (int j = 1; j <= prime[0] && i * prime[j] < maxn; j++) {
            vis[i * prime[j]] = true;
            if (i % prime[j] == 0) break;
        }
    }
    for (int i = 2; i < maxn; ++i) {
        int now = i;
        for (int j = 1; j <= prime[0] && now >= prime[j]; ++j) {
            int cnt = 0;
            while (now % prime[j] == 0) {
                now /= prime[j];
                cnt++;
            }
            num[i] *= ksm(prime[j], (cnt + k - 1) / k * k - cnt);
            if (num[i] < 0) {
                num[i] = -1;
                break;
            }
        }
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    cin >> n >> k;
    init();
    vector<int> a(n);
    for (int i = 0; i < n; ++i) {
        cin >> a[i];
    }
    map<ll, int> mp;
    ll ans = 0;
    for (int i = 0; i < n; ++i) {
        if (num[a[i]] == -1) continue;
        for (int j = 1;; ++j) {
            ll temp = ksm(j, k);
            if (temp == -1 || log10(temp) + log10(num[a[i]]) > 5) {
                break;
            }
            if (mp.count(temp * num[a[i]])) ans += mp[temp * num[a[i]]];
        }
        mp[a[i]]++;
    }
    cout << ans << endl;
    return 0;
}

你可能感兴趣的:(算法,算法每日一练)