将底数质因子分解,假设底数的质因子分解结果为 (x={p_1}^{k_1}{p_2}^{k_2}...{p_n}^{k_n})
令(g=gcd(k_1,k_2,...k_n)) , (e_i=k_i/g)
则(x={({p_1}^{e_1}{p_2}^{e_2}...{p_n}^{e_n})}^{g})
令(S={p_1}^{e_1}{p_2}^{e_2}...{p_n}^{e_n})
所以(x^y={({p_1}^{e_1}{p_2}^{e_2}...{p_n}^{e_n})}^{g*y}=S^{g*y})
所以对于(S)相同的(x^y),有多少个不同的 (g*y) 就有多少个不同的(x^y)
进一步发现,对于不同的(S),只需要知道有多少个不同的(g*y),与(S)本身是多少没有关系。
(y)的取值为([b,b+m)) , 是固定的
(g)最大取19,因为(2^{19}>1e6)
用数组(g[i][j])表示 (g)取([i,j])时,(g*y)的个数
这个可以暴力 (O(log(a+n)*(m))) 计算
最后缺的就是对于每个S,它在(x∈[a,a+n))时,g的取值上界和下界
这个对于每个(x),计算它对应的(S)和(g)
正着扫一遍遇到的第一个就是下界
倒着扫一遍遇到的最后一个就是上界
#include<cstdio>
#include<cstring>
using namespace std;
#define N 1000001
#define M 20
int bl[N],num[N],l[N],r[N];
int fir[N],cnt;
int g[M][M];
bool vis[N*M];
int main()
{
int m,n,a,b,id;
scanf("%d%d%d%d",&m,&n,&a,&b);
for(int i=2;i<n+a;++i)
if(!bl[i])
{
id=1;
bl[i]=i;
num[i]=1;
fir[++cnt]=i;
for(long long j=1ll*i*i;j<n+a;j*=i)
{
bl[j]=i;
num[j]=++id;
}
}
int tot;
for(int i=1;i<M;++i)
{
tot=0;
memset(vis,false,sizeof(vis));
for(int j=i;j<M;++j)
{
for(int k=b;k<m+b;++k)
if(!vis[j*k])
{
vis[j*k]=true;
++tot;
}
g[i][j]=tot;
}
}
for(int i=a;i<n+a;++i)
if(!l[bl[i]]) l[bl[i]]=num[i];
for(int i=n+a-1;i>=a;--i)
if(!r[bl[i]]) r[bl[i]]=num[i];
long long ans=0;
for(int i=1;i<=cnt;++i)
ans+=g[l[fir[i]]][r[fir[i]]];
printf("%lld",ans);
}