伪素数集 学习笔记
lihaoda0120 · · 算法·理论
注意:这个伪素数并不是费马小定理中的伪素数。
这个技巧是 jiangly 在省选比赛讲题时讲的,应该没有很多人知道?
定义
现在有
常用来解决关于
求解伪素数集合
首先因为伪素数集合中的数两两互质,所以对于每个
我们考虑 增量构造,对于一个
关于实现:对于
代码(这样实现集合中应该是不会出现
vector<int> p;//伪素数集合
void insert(int x){
for(int i=0;i<SZ(p);i++){
while(x%p[i]==0)x/=p[i];
int g=gcd(p[i],x);
if(g>1)p[i]/=g,x/=g,insert(g);
}
if(x>1)p.psb(x);
}
复杂度分析
伪素数集合大小显然不会超过所有
伪素数集合中的数的乘积不会超过所有
根据上文,递归一次集合中的所有数的乘积就会除以
其实还有
(这些都是理论复杂度,实际远远跑不满)。
例题:次方数
一个数是
但是现在我们没法将每个
所以要枚举
代码:
#include<bits/stdc++.h>
#define psb push_back
#define fi first
#define se second
#define endl '\n'
#define int __int128
#define pii pair<int,int>
#define SZ(a) ((int)a.size())
using namespace std;
using ll=long long;
namespace IO{template<class T>void read(T &x){char ch=getchar();x=0;bool f=0;while(ch<'0'||ch>'9')ch=getchar();while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=getchar();x=f?-x:x;}template<class T,class ...args>void read(T &x,args &...y){read(x),read(y...);}template<class T>void write(T x){if(x<0)putchar('-'),x=-x;if(x>9)write(x/10);putchar(x%10+'0');}void write(char ch){putchar(ch);}template<class T,class ...args>void write(T x,args ...y){write(x),write(y...);}}
using IO::read;using IO::write;
mt19937_64 rnd(time(NULL));
const int N=505,L=130;
int n,k,a[N];
vector<int> p;
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
void insert(int x){
for(int i=0;i<SZ(p);i++){
while(x%p[i]==0)x/=p[i];
int g=gcd(p[i],x);
if(g>1)p[i]/=g,x/=g,insert(g);
}
if(x>1)p.psb(x);
}
int qpow(int a,int b,int top){
int res=1;
while(b){
if(b&1){if(res>top/a)return -1;res*=a;}
if(b>>=1){if(a>top/a)return -1;a*=a;}
}
return res;
}
int get(int a,int b){
int x=powl(a,1.0/b);
for(int i=x-2;i<=x+2;i++)
if(i>=1&&qpow(i,b,a)==a)return i;
return -1;
}
namespace{
vector<int> w;
vector<pii> fac[N];
int t[N*L];
template<const int MOD,const int N>
struct hash_map{
int head[MOD],cl[N],tg,tc;
struct node{int key,val,nxt;} g[N];
bool find(int x){
int y=x%MOD;
for(int i=head[y];i;i=g[i].nxt)if(g[i].key==x)return 1;
return 0;
}
int &operator[](int x){
int y=x%MOD;
for(int i=head[y];i;i=g[i].nxt)if(g[i].key==x)return g[i].val;
g[++tg]={x,0,head[y]},head[y]=tg,cl[++tc]=y;
return g[tg].val;
}
};
hash_map<100007,N*N> mp;
int solve(){
for(int i=SZ(p);i--;)w.psb(rnd());
for(int i=1;i<=n;i++){
int x=a[i];
for(int j=0;j<SZ(p);j++){
int c=0;
while(x%p[j]==0)x/=p[j],c++;
if(c%=k)fac[i].psb({j,c});
}
}
int ans=0;
for(int i=1;i<=n;i++){
int cnt=0;
for(int j=i;j<=n;j++){
for(pii l:fac[j]){
int p=l.fi,c=l.se;
if(t[p])cnt-=(k-t[p])*w[p];
t[p]=(t[p]+c)%k;
if(t[p])cnt+=(k-t[p])*w[p];
}
ans+=mp[cnt];
}
memset(t,0,sizeof(int)*SZ(p));
cnt=0;
for(int j=i;j>=1;j--){
for(pii l:fac[j]){
int p=l.fi,c=l.se;
if(t[p])cnt-=t[p]*w[p];
t[p]=(t[p]+c)%k;
if(t[p])cnt+=t[p]*w[p];
}
mp[cnt]++;
}
memset(t,0,sizeof(int)*SZ(p));
}
return ans;
}
}
signed main(){
read(n,k);
for(int i=1;i<=n;i++)read(a[i]),insert(a[i]);
for(int &i:p){
for(int j=2;j<=120;j++){
int rt=get(i,j);
if(rt!=-1)i=rt;
}
}
write(solve(),'\n');
return 0;
}