0x01 大体思路
对于一个数,找到和它相乘符合题意的数有多少个,加入答案
0x02 简单推导
可以发现,设当前正处理的数为 $i$,将其分解质因数过后的结果为
$i = {p_1}^{x_1}{p_2}^{x_2}{p_3}^{x_3}...{p_t}^{x_t}$
符合与$i$配对的数$j$,当且仅当将$j$分解质因数后
$j = {p_1}^{y_1}{p_2}^{y_2}{p_3}^{y_3}...{p_t}^{y_t}$
对于每个质因数$p_i$,$x_i+y_i$为$k$的整数倍的时候,$i$与$j$成功配对
因为 $i * j = {p_1}^{x_1+y_1}{p_2}^{x_2+y_2}{p_3}^{x_3+y_3}...{p_t}^{x_t+y_t}$,此时$i*j$必为某数$X^k$
0x03 问题转化
现在的问题变为对于当前处理的$i$,如何找到符合0x02所提到的性质的数有多少个
但是要找对应质因数指数加起来为$k$倍数的,可能加起来为$k$的一倍,也可能两倍...等等很多情况
为了化简这样的问题,这里可以将每个数都分解质因数,然后将每个质因数的指数对$k$取个模,这样就相当于要找到有哪一些数$j$和当前的这个数$i$的对应质因数指数相加起来为$k$就行了。
0x04 实现过程
对于寻找符合要求的数$j$有多少个,这里可以采用的方法为哈希 + std::map
我们对每个数质因数指数情况做一次哈希,指数情况相同的数将得到相同的哈希值
我们使用std::map
存储对应哈希值下有多少个数,然后从后往前处理每一个数
将每一个数分解质因数,边分解的同时,可以边计算出当前这个数$i$的哈希值xhash,以及符合与$i$匹配的$j$的哈希值aimhash。
最后,查找map里面是否有符合要求的$j$的哈希值aimhash,如果有,那么答案加上哈希值为aimhash的数的个数
最后在xhash的位置个数+1
0x05 代码
这里使用的是unsigned long long
自然溢出版本的哈希,$hashbase=2333$
# pragma G++ optimize "O2"
# pragma GCC optimize "O2"
# pragma G++ optimize "O3"
# pragma GCC optimize "O3"
# pragma G++ optimize "Ofast"
# pragma GCC optimize "Ofast"
#include <bits/stdc++.h>
#define LL(x) static_cast<long long>(x)
using namespace std;
#define rg register
typedef long long ll;
typedef unsigned long long ull;
inline int read(){
rg char ch = getchar();
register int ret = 0;
while(!(ch >= '0' && ch <= '9')) ch = getchar();
while(ch >= '0' && ch <= '9') ret = (ret << 3) + (ret << 1) + (ch ^ 48),ch = getchar();
return ret;
}
int n,k;
const int maxn = 200010;
const int hashbase = 2333;
const int maxcnt = 60000;
int a[maxn];
int prime[maxn],cnt=0;
int primeid[maxn];
bool vis[maxn];
ull hashfac[maxn];
void initPrime(){
vis[1] = 1;
for(rg int i=2;i<100010;i++){
if(!vis[i]) {
prime[++cnt] = i;
primeid[i] = cnt;
}
for(rg int j=1;j<=cnt;j++){
if(prime[j] * i >= 100010) break;
vis[prime[j] * i] = true;
if(i % prime[j]) break;
}
}
}
void initHash(){
hashfac[1] = hashbase;
for(rg int i=2;i<=maxcnt;i++) hashfac[i] = hashfac[i-1] * hashbase;
}
map<ull,int> mp;
ll ans = 0;
void solve(int x){
ull xhash = 0;
ull aimhash = 0;
int bakx = x;
for(rg int i=1;i<=cnt;i++){
if(x == 1) break;
if(prime[i] * prime[i] > x) break;
if(x % prime[i] == 0){
int pcnt = 0;
while(x % prime[i] == 0){
x /= prime[i];
pcnt++;
if(pcnt >= k) pcnt -= k;
}
xhash += hashfac[i] * pcnt;
if(pcnt != 0){
aimhash += hashfac[i] * (k - pcnt);
}
}
}
if(x != 1){
xhash += hashfac[primeid[x]];
aimhash += hashfac[primeid[x]] * (k-1);
}
if(mp.count(aimhash)){
ans += mp[aimhash];
}
mp[xhash]++;
}
int main(){
n = read(),k = read();
for(rg int i=1;i<=n;i++){
a[i] = read();
}
initPrime();
initHash();
for(rg int i=n;i>=1;i--){
solve(a[i]);
}
printf("%lld\n",ans);
return 0;
}
解得好
By 王海宇 at November 23rd, 2020 at 01:29 pm.
来了
By 某韦 at March 18th, 2020 at 07:23 pm.