timus 1673 & phi & 反phi

题意:

给定 \(k\),求一个最小的 \(n\) 使得有恰好 \(k\)\(i\in [1,n]\),满足对于所有 \(j\in [1,n]\),都有 \(x\) 满足 \(ix=j\mod n\) 并且 \(ix\le n^2\)​。里面所有数都是正整数。

Sol:

我们考虑 \(\gcd(x,n)>1\)\(x\)。因为 \(\gcd(x,n)>1\),所以 \(\operatorname{lcm}(x,n)<n^2\),设为 \(xt\)。因为 \(t<n\),所以 \(x\)\(1\sim t\) 倍最多不会有超过 \(t\) 个不同的剩余类。但是 \(t+1\) 倍的 \(x\) 又和 \(1\) 倍的 \(x\) 本质相同,构成了循环,所以\(\gcd(x,n)>1\)\(x\) 不行。因此 \(\gcd(x,n)=1\) 可以。而我们知道 \(\sum_{x=1}^n [\gcd(x,n)=1]=k\),所以这个题转化成求 \(\varphi(n)=k\) 的最小 \(n\)

插播:\(\varphi(n)\) 是什么?

欧拉函数 \(\varphi(n)\)\(1\sim n\) 种和 \(n\) 互素的元素个数。\(\varphi(n)\)​ 是积性函数。

\(\varphi(n)\) 的显性公式:\(\varphi(p)=p-1,\varphi(p^k)=p^k-p^{k-1}\)

\[\begin{aligned} \varphi(n)=&\varphi(p_1^{a_1})\cdots \varphi(p_t^{a_t})\\=&(p_1^{a_1}-p_1^{a_1-1})\cdots (p_t^{a_t}-p_{t}^{a_t-1})\\=&p_1^{a_1}(1-\frac{1}{p_1})\cdots p_t^{a_t}(1-\frac{1}{p_t})\\=&n(1-\frac{1}{p_1})\cdots (1-\frac{1}{p_t})\\=&n\prod(1-\frac{1}{p}) \end{aligned} \]

因此

\[\begin{aligned} \varphi(n)=&n\prod(1-\frac{1}{p})\\ =&p_1^{a_1}\cdots p_t^{a_t}\prod_i \frac{p_i-1}{p_i}\\ =&p_1^{a_1-1}\cdots p_t^{a_t-1}\prod_i (p_i-1)\\ =&\prod_i p_i^{a_i-1}(p_i-1) \end{aligned} \]

所以因为 \(\varphi(n)=k\),所以 \(p_i-1\mid k\)

我们可以预处理 \(\sqrt{k}\) 以内的质数,\(\sqrt{k}\) 以外的指数单独判。每一次看要不要加上一个质数,前提条件是 \(p_i-1\mid k\)

#include <bits/stdc++.h>

using namespace std;

using ll = long long;

const int N = 1e5+5;
const int M = 50000;
const ll inf = 2e12;

int lim,pr[N],vis[N],cnt;

void init(){
	for (int i=2; i<=M; i++){
		if (!vis[i]){
			pr[++cnt]=i;
		}
		for (int j=1; j<=cnt && i*pr[j]<=M; j++){
			vis[i*pr[j]]=1;
			if (i%pr[j]==0){
				break;
			}
		}
	}
}

bool isp(ll x){
	for (ll i=2; i*i<=x; i++){
		if (x%i==0){
			return 0;
		}
	}
	return 1;
}

ll ans=inf;

void dfs(int p,int r,ll c){
	if (c>=ans){
		return;
	}
	if (r==1){
		ans=c;
		return;
	}
	if (r>lim && isp(r+1)){
		ans=min(ans,c*(r+1));
	}
	for (int i=p+1; pr[i]-1<=min(lim,r); i++){
		if (r%(pr[i]-1)==0){
			int nr=r/(pr[i]-1);
			ll nc=c*pr[i];
			dfs(i,nr,nc);
			while (nr%pr[i]==0){
				nr/=pr[i];
				nc*=pr[i];
				dfs(i,nr,nc);
			}
		}
	}
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);

	init();
	int k;
	cin>>k;
	lim=sqrt(k+1);
	dfs(0,k,1);
	if (ans==inf){
		cout<<0<<"\n";
	}
	else{
		cout<<ans<<"\n";
	}
	return 0;
}

其实我也不知道复杂度是啥。但是在 \(k\le 2\cdot 10^9\) 跑过了。

posted @ 2024-06-07 16:37  SFlyer  阅读(2)  评论(0编辑  收藏  举报