Link
https://jzoj.net/senior/#main/show/3760
Description
欧拉函数 φ(n) 定义为不超过正整数 n 并且与 n 互素的整数的数目。
可以证明 φ(n) = n ∗ ∏ (1 − 1 / pi). 其中 pi(1 <= i <= k)是 n 的全部素因子。
已知 y,求最小的自然数 x 使得 φ(x) = y.
多组询问。
Solution
30分:
可以枚举每一个x,判断所得出来的φ(x)是否等于y。可证x≤7y
60分:
可能是某些神奇的算法,或者是给没有int64的人一点分
100分:
这里有三种解题思路
三种都可以用搜索来做,也可以使用动态规划来做。
动态规划公式:F[i,j]表示前i个可能的质因子,分解后得到状态S的最小x’
(1)欧拉函数定义
根据欧拉函数的定义,很显然可以得到如下两条性质:
①φ(x)=x-1......................当x是素数时
②φ(xy)=φ(x)*φ(y)..........对任何情况都是成立的
于是,分别得出如下结论:
根据①:x的质因数可能是y的约数加一,
根据②:x的质因数可能是y的质因数。
可能有点难理解,但的确如此。
(2)分解欧拉函数公式
我们可以尝试一下分解每个式子。
x=p1q1*p2q2*...pnqk(p数组为x质因子,q数组为每个质因子的个数)
显然如下
φ(x)=x*(p1-1/p1)(p2-1/p2).....(pk-1/pk)..................................公式
φ(x)=p1q1*p2q2*...pn^qn*(p1-1/p1)(p2-1/p2).....(pk-1/pk).......将x带入
当q1=q2=....=qk=1时,剩下的,就只有(p1-1)*(p2-1)*...(pk-1)
当有某些q数组的元素大于一时,就是上面那些式子,再多乘那些消掉以后多出来的pxqx,即(p1-1)*(p2-1)*...(pk-1)*pxqx,注意,这里x只是某一个举例子的
所以可以发现,x的质因数可能是y的约数加一,x的质因数可能是y的质因数。
(3)分解欧拉函数公式
同样是拆分式子,跟(2)差不多的,
φ(x)=∏piqi * ∏(1-1/pi)
φ(x)=∏[ piqi (1-1/pi) ]............合并连乘的
φ(x)=∏[ piqi-1 (1-1/pi)*pi ]...拆一个pi出来与后面的式子相乘
φ(x)=∏[ piqi-1 (pi-1) .............约分得到的
同样可以得到上面的结论(x的质因数可能是y的约数加一,x的质因数可能是y的质因数),递归或者动态规划做就行了
剪枝
可以加快排,大小值,记忆化来剪枝。
Code(2)
uses math; var x,min:int64; n,t,i,j,k:longint; prime,bz:array[0..10000] of int64; procedure dg(k,x,now:int64); var s,ss:qword; i:longint; begin if now>min then exit; if x=1 then begin min:=now; exit; end; if k>prime[0] then exit; s:=1; for i:=0 to 40 do begin if s>x then break; if s>x/prime[k] then break; if x mod (s*prime[k])<>0 then break; bz[k]:=i; dg(k+1,x div (s*prime[k]),now*s*(prime[k]+1)); bz[k]:=-1; s:=s*(prime[k]+1); end; dg(k+1,x,now); end; function pd(x:int64):boolean; var i:longint; begin for i:=2 to trunc(sqrt(x)) do if x mod i=0 then exit(false); exit(true); end; procedure q(l,r:longint); var t,mid:int64; i,j:longint; begin i:=l; j:=r; mid:=prime[(l+r) shr 1]; while i<j do begin while prime[i]>mid do inc(i); while prime[j]<mid do dec(j); if i<=j then begin t:=prime[i]; prime[i]:=prime[j]; prime[j]:=t; inc(i); dec(j); end; end; if i<r then q(i,r); if l<j then q(l,j); end; begin readln(n); for j:=1 to n do begin readln(x); fillchar(prime,sizeof(prime),0); for i:=1 to trunc(sqrt(x)) do if x mod i=0 then begin if pd(i+1) then begin inc(prime[0]); prime[prime[0]]:=i; end; if x div i<>i then begin if pd(x div i+1) then begin inc(prime[0]); prime[prime[0]]:=x div i; end; end; end; q(1,prime[0]); fillchar(bz,sizeof(bz),255); min:=21099511627776; dg(1,x,1); writeln(min); end; end.
uses math; const maxn=1000000; var pr,flag:array[0..10000] of int64; z,have:array[0..100000] of int64; bz:array[0..1000000] of boolean; n,nn,tot,ans:int64; i,j,p:longint; procedure dfs(k,sum,max:int64; flag2:boolean); begin if max*sum>=ans then exit; if sum=1 then begin ans:=min(ans,max); exit; end; if k>have[0]+pr[0] then exit; if k<=have[0] then begin if (have[k]<=1) or (sum mod have[k]<>0) then dfs(k+1,sum,max,flag2) else begin dfs(k+1,sum div have[k],max*(have[k]+1),true); dfs(k+1,sum,max,flag2); end; end else begin if flag2 then exit; inc(flag[have[k]]); if flag[have[k]]=1 then begin if sum mod (have[k]-1)=0 then dfs(k+1,sum div (have[k]-1),max*have[k],flag2); end else if sum mod have[k]=0 then dfs(k+1,sum div have[k],max*have[k],flag2); dec(flag[have[k]]); dfs(k+1,sum,max,flag2); end; end; function pd(x:int64):boolean; begin for j:=1 to z[0] do begin if sqr(z[j])>x then exit(true); if x mod z[j]=0 then exit(false); end; end; begin for i:=2 to maxn do begin if not bz[i] then begin inc(z[0]); z[z[0]]:=i; end; for j:=1 to z[0] do begin if z[j]*i>maxn then break; bz[z[j]*i]:=true; if i mod z[j]=0 then break; end; end; readln(tot); for p:=1 to tot do begin have[0]:=0; pr[0]:=0; readln(n); for i:=trunc(sqrt(n)) downto 1 do if n mod i=0 then begin if pd(i+1) then begin inc(have[0]); have[have[0]]:=i; end; if i=n div i then continue; if pd(n div i+1) then begin inc(have[0]); have[have[0]]:=n div i; end; end; nn:=n; for i:=1 to z[0] do begin if sqr(z[i])>nn then break; if nn mod z[i]=0 then begin inc(pr[0]); have[pr[0]+have[0]]:=z[i]; end; while nn mod z[i]=0 do begin inc(pr[0]); have[pr[0]+have[0]]:=z[i]; nn:=nn div z[i]; end; end; ans:=maxlongint*maxlongint; dfs(1,n,1,false); writeln(ans); end; end.