[cf698F]Coprime Permutation

记$P$为$[1,n]$中所有素数构成的集合,$g(n)$为$n$所有素因子乘积(特别的,$g(1)=1$)

对于一个合法排列$\{q_{i}\}$,注意到$\forall x\in P\cup\{1\},q_{x}$两两互素,也即每一个素因子至多只能在其中出现一次,分析数量不难得到每一个数至多只能包含一个素因子(注意仅有1不包含素因子)

换言之,$\forall x\in P\cup \{1\},g(q_{x})$恰为$P\cup \{1\}$的一个排列

不妨假设已经确定这些$g(q_{x})$,那么有$g(q_{i})=\prod_{x\in P\cup\{1\},\gcd(x,i)\ne 1}g(q_{x})$(其中$i\ne 1$,注意到包含$g(q_{x})$这个素因子当且仅当$\gcd(x,i)\ne 1$,同时这样考虑了$P$中所有素数,即正确)

进一步的,对于$g(x)=g(y)$的$x$和$y$在是否互素的判定中是等价的,因此此时已经可以确定$\{q_{i}\}$合法,并且仅需保证数量相同(即$\forall x,\sum_{g(i)=x}1=\sum_{g(q_{i})=x}1$),其内部是可以任意排列的

此时,问题即变为怎样的$P\cup \{1\}$的排列(填入$\forall x\in P\cup\{1\},g(q_{x})$)能保证"数量相同"

(下面较详细地分析了细节,如果感性理解可以直接跳过看结论)

对"数量相同"的式子容斥,前者即为
$$
\sum_{g(i)=x}1=\begin{cases}0&\mu(x)=0\\\sum_{S_{0}\subseteq S\subseteq P}(-1)^{|S|-|S_{0}|}\sum_{(\prod_{p\in S}p)\mid g(i)}1&\mu(x)\ne 0\end{cases}
$$
($S_{0}$为$x$素因子集合,另外注意$\mu(\prod_{p\in S}p)\ne 0$)

类似地,后者$\sum_{g(q_{i})=x}1$只需要将式子中的$g(i)$均改为$g(q_{i})$即可

由此,"数量相同"的充分条件即$\forall \mu(x)\ne 0,\sum_{x\mid g(i)}1=\sum_{x\mid g(q_{i})}1$,同时显然这也是必要的

关于前者,由于$\mu(x)\ne 0$,那么$x\mid g(i)$即等价于$x\mid i$,前者也即为$\lfloor\frac{n}{x}\rfloor$

关于后者,再令$S_{0}=\{p\mid p\in P\cup\{1\}$且$q_{p}\ne 1,g(q_{p})\mid x\}$,那么$x\mid g(q_{i})$(其中$i\ne 1$)根据$g(q_{i})$的式子即等价于$\forall p\in S_{0},\gcd(p,i)\ne 1$,又因为$p\in S_{0}\subseteq P\cup \{1\},\gcd(p,i)\ne 1$也即$p\ne 1$且$p\mid i$

换言之,后者也即为$\begin{cases}n&(x=1)\\ [x\mid g(q_{1})]+\begin{cases}0&q_{1}\ne 1,g(q_{1})\mid x\\\lfloor\frac{n}{\prod_{p\in S_{0}}p}\rfloor&otherwise\end{cases}&(x\ne 1)\end{cases}$

对这三类分别讨论(注意需要同时满足),具体如下——

1.$x=1$时必然成立(与$g(q_{x})$无关)

2.$x\ne 1$且$q_{1}\ne 1,g(q_{1})\mid x$时,取$x=g(q_{1})$即有$\lfloor\frac{n}{g(q_{1})}\rfloor=1$,推出$g(q_{1})>\lfloor\frac{n}{2}\rfloor$,同时此时$q_{1}$必然恰为$g(q_{1})$(而不能是$g(q_{1})^{\alpha}$),同时此时$x$必然为$g(q_{1})$,也即成立(另外注意$q_{1}$还可以等于1)

3.$x\ne 1$且$otherwise$,取$x$为$\ne q_{1}$的素数,令$p$满足$p\in P\cup\{1\}$且$g(q_{p})=x$,即有$\lfloor\frac{n}{x}\rfloor=\lfloor\frac{n}{p}\rfloor$,并且$x\le \sqrt{n}$时此式成立必然要有$p=x$,证明如下:

若$xp>n$,则$\lfloor\frac{n}{p}\rfloor<x\le \sqrt{n}\le \lfloor\frac{n}{x}\rfloor$,即不相等

若$xp\le n$,不妨假设$x<p$,则$\lfloor\frac{n}{x}\rfloor=p+\lfloor\frac{n-xp}{x}\rfloor>x+\lfloor\frac{n-xp}{p}\rfloor$

而在此条件下,考虑$x$即是要求$\lfloor\frac{n}{x}\rfloor=\lfloor\frac{n}{\prod_{p\in S_{0}}p}\rfloor$,此时将$x$的素因子和$p$对应,其中仅有$>\sqrt{n}$的项不相同,这至多存在一项且被$n$除后也相同,再除以相同的数显然仍相同

综上,"数量相同"当且仅当满足以下条件:

1.$q_{1}=1$或$q_{1}\in P$且$q_{1}>\lfloor\frac{n}{2}\rfloor$

2.$\forall x\in P\cup\{1\}$且$x\ne q_{1}$,有$\lfloor\frac{n}{x}\rfloor=\lfloor\frac{n}{p}\rfloor$(其中$p\in P\cup\{1\}$且$g(q_{p})=x$)

这样填完这个排列后,若$q_{1}=1$即已经填完,$q_{1}\ne 1$即还剩下一个位置,该位置(下标)为$>\lfloor\frac{n}{2}\rfloor$的素数,并且即要填剩下的1,因此实际上即将$\lfloor\frac{n}{1}\rfloor$看作1就可以归为一种情况

令$h(x)=\begin{cases}1&(x=1)\\\lfloor\frac{n}{x}\rfloor&(x\in P)\end{cases}$,那么"数量相同"当且仅当$\forall x\in P\cup\{1\},h(x)=h(g(q_{x}))$,换言之可以看作$h(x)$相同的数内部可以任意排列

接下来,考虑若干个给定的$q_{i}$,处理过程如下——

1.$i$和$q_{i}$不超过$\sqrt{n}$的素因子(存在性)应该相同,且必须都存在/不存在$>\sqrt{n}$的素因子(显然至多一个)

2.(若$i$和$q_{i}$都存在$>\sqrt{n}$的素因子)令$p_{1},p_{2}$分别为$i$和$q_{i}$大于$\sqrt{n}$的素因子,则需要满足$\lfloor\frac{n}{p_{1}}\rfloor=\lfloor\frac{n}{p_{2}}\rfloor$,并且在$x\in P\cup\{1\}$的排列中强制$g(q_{p_{1}})=p_{2}$,记录这样的关系(防止重复)并将$h(p_{2})$所在组去掉一个

($\le \sqrt{n}$的素因子不需要减小,因为其本身必须对应相同)

3.对于最后$g(q_{i})$确定后的排列中,$g(q_{i})$所在的组减少一个数

最终,将两者排列(求阶乘)相乘即可

时间复杂度为$o(n)$,可以通过

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 1000005
 4 #define mod 1000000007
 5 #define ll long long
 6 int n,ans,a[N],fac[N],vis[N],p[N],mx[N],Mn[N],f[N],r0[N],r1[N],cnt[N],cnt0[N];
 7 int main(){
 8     fac[0]=mx[1]=Mn[1]=1;
 9     for(int i=1;i<N;i++)fac[i]=(ll)fac[i-1]*i%mod;
10     for(int i=2;i<N;i++){
11         if (!vis[i]){
12             p[++p[0]]=i;
13             mx[i]=Mn[i]=i;
14         }
15         for(int j=1;(j<=p[0])&&(i*p[j]<N);j++){
16             vis[i*p[j]]=1;
17             mx[i*p[j]]=mx[i];
18             if (i%p[j])Mn[i*p[j]]=Mn[i]*p[j];
19             else{
20                 Mn[i*p[j]]=Mn[i];
21                 break;
22             }
23         }
24     }
25     scanf("%d",&n);
26     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
27     for(int i=1;i<=n;i++)cnt[Mn[i]]++;
28     f[1]=1;
29     for(int i=1,j;(i<=p[0])&&(p[i]<=n);i=j){
30         j=i+1,f[p[i]]=p[i];
31         while ((j<=p[0])&&(p[j]<=n)&&(n/p[i]==n/p[j]))f[p[j++]]=p[i];
32         if ((j>p[0])||(p[j]>n)){
33             for(int k=i;k<j;k++)f[p[k]]=1;
34         }
35     }
36     cnt0[1]++;
37     for(int i=1;(i<=p[0])&&(p[i]<=n);i++)cnt0[f[p[i]]]++;
38     for(int i=1;i<=n;i++)
39         if (a[i]){
40             int x=i,y=a[i];
41             cnt[Mn[y]]--;
42             if ((f[mx[x]]!=f[mx[y]])||(Mn[x]/mx[x]!=Mn[y]/mx[y])){
43                 printf("0\n");
44                 return 0;
45             }
46             if ((x==1)||((ll)mx[x]*mx[x]>n)){
47                 if ((!r0[mx[x]])&&(!r1[mx[y]])){
48                     cnt0[f[mx[x]]]--;
49                     r0[mx[x]]=mx[y],r1[mx[y]]=mx[x];
50                 }
51                 if ((r0[mx[x]]!=mx[y])||(r1[mx[y]]!=mx[x])){
52                     printf("0\n");
53                     return 0;
54                 }
55             }
56         }
57     ans=1;
58     for(int i=1;i<=n;i++)ans=(ll)ans*fac[cnt[i]]%mod*fac[cnt0[i]]%mod;
59     printf("%d\n",ans);
60     return 0;
61 }
View Code

 

posted @ 2021-10-19 10:46  PYWBKTDA  阅读(293)  评论(0编辑  收藏  举报