Loading

[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;
}
posted @ 2022-12-14 21:26  zhouhuanyi  阅读(29)  评论(0)    收藏  举报