cogs 2405 [noi2016]循环之美 杜教筛+DP

标签(空格分隔): 数论


题目链接1
题目链接2
题目链接3
一个推论:
一个最简分数\(\frac{x}{y}\)在k进制下是纯循环的,当且仅当\(\gcd(y,k)=1\)
证明:
不妨设\(x\leq y\)。最简分数即\(\gcd(x,y)=1\)。纯循环即小数位的第1位属于循环节,那么就是存在p满足\(x\equiv x\times k^p \pmod y\)即余数出现循环是从小数点对应第一位的余数开始的。
由于\((x,y)=1\),所以当且仅当存在p使\(1 \equiv k^p \pmod y\),那么\(\frac{x}{y}\)就是纯循环的。
而这个结论成立当且仅当\((k,y)=1\),所以得证。

有了这个推论,我们要求的式子一目了然:

\[ \sum_{i=1}^{n}\sum_{j=1}^{m}[(i,j)=1]\cdot[(j,k)=1] \]

然后就是数学式子的推导了。我尽可能写的在清晰的情况下易懂。

\[\begin{eqnarray*} ans & = & \sum_{i=1}^n\sum_{j=1}^m[(i,j)=1]\cdot[(j,k)=1]\\ & = & \sum_{i=1}^n\sum_{j=1}^m\sum_{d|i,d|j}{\mu(d)}\cdot[(j,k)=1]\\ & = & \sum_{d=1}^{min(n,m)}\mu(d)\cdot\left\lfloor\frac{n}{d}\right\rfloor\sum_{j=1}^{m}[d|j]\cdot[(j,k)=1]\\ & = & \sum_{d=1}^{min(n,m)}\mu(d)\cdot\left\lfloor\frac{n}{d}\right\rfloor\sum_{j=1}^{\left\lfloor\frac{m}{d}\right\rfloor}[(jd,k)=1]\\ & = & \sum_{d=1}^{min(n,m)}[(d,k)=1]\cdot\mu(d)\left\lfloor\frac{n}{d}\right\rfloor\sum_{j=1}^{\left\lfloor\frac{m}{d}\right\rfloor}[(j,k)=1]\\ \end{eqnarray*} \]

\(f(n)=\sum_{i=1}^{n}[(i,k)=1]\)
根据\(\gcd(a,b)=\gcd(a+b,b)=\gcd(a+kb,b)\),我们可以知道\(f(n)=\left\lfloor\frac{n}{k}\right\rfloor\cdot f(k) + f(n\bmod k)\),所以\(f\)函数预处理\(O(k\log k)\),查询\(O(1)\)

\[\begin{align} ans = \sum_{d=1}^{min(n,m)}[(d,k)=1]\cdot\mu(d)\left\lfloor\frac{n}{d}\right\rfloor f\left(\left\lfloor\frac{m}{d}\right\rfloor\right) \\ \end{align} \]

\(S(n)=\sum_{i=1}^{n}[(i,k)=1]\cdot \mu(i)\),考虑通过类似洲阁筛的DP求出\(S\)
定义\(s(i,n)\)表示小于等于\(n\)且与\(k\)的前\(i\)种质因子互质的数\(d\)\(\mu(d)\)之和,初始化\(s(i,n)=\sum_{d=1}^{n}\mu(d)\),用杜教筛即可。

\[ s(i,n)=s(i-1,n)-\mu(p_i)\cdot s(i,\left\lfloor\frac{n}{p_i}\right\rfloor) \]

还是比较好理解的。意思就是从与前\(i-1\)互质的所有\(\mu\)中减去不与\(i\)互质的。由于\(\mu\)不是完全积性函数,所以要求除去\(p_i\)后与前i互质而不是与前\(i-1\)互质,因此要注意第二维转移应是递增转移。

根据\((1)\)式可得,\(s(i,n)\)函数的第二维只有\(O(\sqrt{n}+\sqrt{m})\)种取值,所以DP的复杂度是预处理\(O(n^{\frac{2}{3}})\)+DP\(O(w(k)\cdot (\sqrt{n}+\sqrt{m}))\)(\(w(k)\)表示k的不同质因子个数,由于\(k\leq 2000\),\(w(k)\)最大也就是\(4\)),也是本题最终复杂度。

code

#include<stdio.h>
#include<set>
#include<map>
#include<algorithm>
#include<math.h>
using namespace std;
typedef long long LL;
int n,m,K,maxn;
int mu[1000010];
bool flag[1000010];
int prime[500010],tot=0;
void Init(){
	mu[1]=1;
	for(int i=2;i<=maxn;++i){
		if(!flag[i]){
			prime[++tot]=i;
			mu[i]=-1;
		}
		for(int j=1;j<=tot&&i*prime[j]<=maxn;++j){
			flag[i*prime[j]]=true;
			if(i%prime[j]==0) break;
			mu[i*prime[j]]=-mu[i];
		}
	}
	for(int i=1;i<=maxn;++i) mu[i]+=mu[i-1];
}
map<int,int> M;
int Gcd(int a,int b){return b==0?a:Gcd(b,a%b);}
int Mu(int x){
	if(x<=maxn) return mu[x];
	if(M.count(x)) return M[x];
	int ans=0;
	for(int i=2,j;i<=x;i=j+1){
		j=x/(x/i);
		ans+=(j-i+1)*Mu(x/i);
	}
	M[x]=1-ans;
	return 1-ans;
}
#define R(x) (x<=sqr?x:cnt-(n/x)+1)
int H[120010],cnt;
map<int,int> R;
set<int> P;
int p[10],tmp,F[2010];
inline int f(int x){return (x/K)*F[K]+F[x%K];}
int S[120010];
int main(){
	freopen("cyclic.in","r",stdin);
	freopen("cyclic.out","w",stdout);
	
	scanf("%d%d%d",&n,&m,&K);
	maxn=(int)pow(n,2.0/3.0);
	Init();
	
	for(int i=1;i*i<=n;++i) P.insert(i),P.insert(n/i);
	for(int i=1;i*i<=m;++i){
		if(i<=n) P.insert(i);
		if(m/i<=n) P.insert(m/i);
	}
	for(set<int>::iterator iter=P.begin();iter!=P.end();++iter){
		R[*iter]=++cnt;
		H[cnt]=*iter;
	}
	for(int i=1;i<=cnt;++i) S[i]=Mu(H[i]);
	for(int i=1;i<=K;++i) F[i]=F[i-1]+(Gcd(i,K)==1);
	int x=K;
	for(int i=2;i*i<=x;++i){
		if(x%i==0){
			p[++tmp]=i;
			while(x%i==0) x/=i;
		}
	}
	if(x>1) p[++tmp]=x;
	for(int i=1;i<=tmp;++i){
		for(int j=1;j<=cnt;++j){
			if(H[j]<p[i]) continue;
			S[j]+=S[R[H[j]/p[i]]];
		}
	}
	LL Last=0,Now,ans=0;
	for(int i=1,j,y=min(n,m);i<=y;i=j+1){
		j=min(n/(n/i),m/(m/i));
		Now=S[R[j]];
		ans+=(LL)(Now-Last)*(n/i)*f(m/i);
		Last=Now;
	}
	printf("%lld\n",ans);
	getchar(); getchar();
	fclose(stdin); fclose(stdout);
	return 0;
}
原文地址:https://www.cnblogs.com/kito/p/7009060.html