[NOI2016]循环之美
链接:https://www.luogu.com.cn/problem/P1587
题目描述:求有多少个\(\frac{a}{b}(1<=a<=n,1<=b<=m)\)在\(k\)进制下是纯循环小数\((注意:相等的数只算一次)\)。
题解:可以发现\(\frac{a}{b}(1<=a<=n,1<=b<=m)\)在\(k\)进制下是纯循环小数当且仅当\(\frac{a}{b}\)化为最简分数后分母与\(k\)互质。我们可以只在最简分数处算,则原问题化为求\(\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)==1][gcd(j,k)==1]\)
\(\qquad\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)==1][gcd(j,k)==1]\)
\(=\sum_{i=1}^{n}\sum_{j=1}^{m}\sum_{d|gcd(i,j)}μ(d)[gcd(j,k)==1]\)
\(=\sum_{d=1}^{n}μ(d)\lfloor \frac{n}{d}\rfloor\sum_{d|j}[gcd(j,k)==1]\)
\(=\sum_{d=1}^{n}μ(d)\lfloor \frac{n}{d}\rfloor\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}[gcd(dj,k)==1]\)
\(=\sum_{d=1}^{n}μ(d)\lfloor \frac{n}{d}\rfloor [gcd(d,k)==1]\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}[gcd(j,k)==1]\)
令\(f(n,k)=\sum_{i=1}^{n}[gcd(i,k)==1],g(n,k)=\sum_{i=1}^{n}μ(i)[gcd(i,k)==1]\)
则原式可以用数论分块快速求出,考虑如何快速求出这两个函数,可以利用递归的思想,将\(k\)推向\(k/p\)(\(p\)为\(k\)的一个质因子)。
\(f(n,k)=\sum_{i=1}^{n}[gcd(i,k)==1]\)
\(=\sum_{i=1}^{n}[gcd(i,\frac{k}{p})==1]-\sum_{i=1}^{n}[gcd(i,\frac{k}{p})==1][p|i]\)
\(=f(n,k/p)-\sum_{i=1}^{n}[gcd(i,\frac{k}{p})==1][p|i]\)
\(=f(n,k/p)-\sum_{i=1}^{\lfloor \frac{n}{p} \rfloor}[gcd(ip,\frac{k}{p})==1]\)
当\(k\)中含有两个质因子\(p\)时,该式就等于\(f(n,k/p)\)。
当\(k\)中含有一个质因子\(p\)时
原式\(=f(n,k/p)-\sum_{i=1}^{\lfloor \frac{n}{p} \rfloor}[gcd(i,\frac{k}{p})==1]\)
\(=f(n,k/p)-f(\lfloor \frac{n}{p} \rfloor,k/p)\)
\(g(n,k)=\sum_{i=1}^{n}μ(i)[gcd(i,k)==1]\)
\(=\sum_{i=1}^{n}μ(i)[gcd(i,\frac{k}{p})==1]-\sum_{i=1}^{n}μ(i)[gcd(i,\frac{k}{p})==1][p|i]\)
\(=g(n,k/p)-\sum_{i=1}^{n}μ(i)[gcd(i,\frac{k}{p})==1][p|i]\)
\(=f(n,k/p)-\sum_{i=1}^{\lfloor \frac{n}{p} \rfloor}μ(ip)[gcd(ip,\frac{k}{p})==1]\)
当\(k\)中含有两个质因子\(p\)时,该式就等于\(g(n,k/p)\)。
当\(k\)中含有一个质因子\(p\)时
原式\(=g(n,k/p)-\sum_{i=1}^{\lfloor \frac{n}{p} \rfloor}μ(i)μ(p)][gcd(i,p)==1][gcd(i,\frac{k}{p})==1]\)
\(=g(n,k/p)-μ(p)\sum_{i=1}^{\lfloor \frac{n}{p} \rfloor}μ(i)[gcd(i,k)==1]\)
\(=g(n,k/p)+\sum_{i=1}^{\lfloor \frac{n}{p} \rfloor}μ(i)[gcd(i,k)==1]\)
\(=g(n,k/p)+g(\lfloor \frac{n}{p} \rfloor,k)\)
#include<iostream>
#include<cstdio>
#include<map>
#define N 10000000
using namespace std;
int n,m,k,miu[10000001],prime[10000001],v[10000001],len;
map<long long,long long>p;
map<pair<long long,int>,long long>F;
map<pair<long long,int>,long long>G;
inline void prework()
{
miu[1]=1;
for (int i=2;i<=N;++i)
{
if (!v[i])
{
miu[i]=-1;
v[i]=i;
prime[++len]=i;
}
for (int j=1;j<=len;++j)
{
if (prime[j]*i>N||prime[j]>v[i])
break;
v[i*prime[j]]=prime[j];
if (i%prime[j]==0)
break;
else
miu[i*prime[j]]=-miu[i];
}
}
for (int i=2;i<=N;++i)
miu[i]+=miu[i-1];
return;
}
inline long long sum_miu(register long long n)
{
if (n<=N)
return miu[n];
if (p.find(n)!=p.end())
return p[n];
long long res=1,last;
for (int i=2;i<=n;i=last+1)
{
last=n/(n/i);
res-=(last-i+1)*sum_miu(n/i);
}
p.insert(make_pair(n,res));
return res;
}
inline long long f(register long long n,register int k)
{
if (F.find(make_pair(n,k))!=F.end())
return F[make_pair(n,k)];
if (k==1)
return n;
if ((k/v[k])%v[k]==0)
return f(n,k/v[k]);
register long long ans=f(n,k/v[k])-f(n/v[k],k/v[k]);
F.insert(make_pair(make_pair(n,k),ans));
return ans;
}
inline long long g(register long long n,register int k)
{
if (G.find(make_pair(n,k))!=G.end())
return G[make_pair(n,k)];
if (n==0)
return 0;
if (k==1)
return sum_miu(n);
if ((k/v[k])%v[k]==0)
return g(n,k/v[k]);
register long long ans=g(n,k/v[k])+g(n/v[k],k);
G.insert(make_pair(make_pair(n,k),ans));
return ans;
}
int main()
{
register long long ans=0,last;
prework();
scanf("%d%d%d",&n,&m,&k);
for (register int i=1;i<=min(n,m);i=last+1)
{
last=min(n/(n/i),m/(m/i));
ans+=(g(last,k)-g(i-1,k))*(n/i)*f(m/i,k);
}
printf("%lld\n",ans);
return 0;
}
本文来自博客园,作者:zhouhuanyi,转载请注明原文链接:https://www.cnblogs.com/zhouhuanyi/p/16983622.html

浙公网安备 33010602011771号