题意:构造一个1到n的排列a1,a2,......an 满足对于任意i,j满足1<=i<j<=n ai,aj 互质当且仅当i,j互质。a中一些元素已知,求可以构造的排列个数。
对于两个质数p1,p2,如果有这两个质数因子的数的个数相等(既n/p1=n/p2)那么可以将所有数的质因子中出现的这两个质数交换。
如果两个数包含相同的质因子,那么可以将两个数交换。
如果第i个数ai已知:
如果ai质因子个数和i的质因子个数不等,无解。
如果ai的第j个质因子和i的第j个质因子出现次数不等,无解。
注意设ai有pi个质因子,这里只需要判断前pi-1个质因子是否相等和第pi个质因子出现次数是否相等即可。因为前pi-1个质因子小于根号n,对于小于根号n的两个质数p1,p2:n/p1和n/p2不等。
如果最后一个质因子已经有对应的质因子,无解。
最后阶乘统计答案即可。
注意处理1的问题。
#include <bits/stdc++.h>
using namespace std;
#define mod 1000000007
#define ll long long
#define N 1100000
int n;
ll jc[N],ans;
int a[N],num[N],num1[N],pos[N],mul[N];
int pre[N],nex[N];
vector<int>v[N];
void quit(){puts("0");exit(0);}
int main()
{
//freopen("tt.in","r",stdin);
scanf("%d",&n);
jc[0]=1;
for(int i=1;i<=n;i++)jc[i]=jc[i-1]*i%mod;
for(int i=1;i<=n;i++)mul[i]=1;
for(int i=2,pre=0;i<=n;i++)
if(!v[i].size())
{
num[n/i]++;pos[i]=n/i;
for(int j=i;j<=n;j+=i)
v[j].push_back(i),mul[j]*=i;
}
for(int i=1;i<=n;i++)num1[mul[i]]++;
num[1]++;pos[1]=1;
v[1].push_back(1);
for(int i=1,x,y;i<=n;i++)
{
scanf("%d",&a[i]);
if(a[i]==0)continue;
num1[mul[a[i]]]--;
if(v[a[i]].size()!=v[i].size())quit();
for(int j=0;j<v[i].size()-1;j++)
if(v[a[i]][j]!=v[i][j])quit();
x=v[a[i]].back();y=v[i].back();
if(pos[x]!=pos[y])quit();
if(pre[x]&&pre[x]!=y)quit();
if(nex[y]&&nex[y]!=x)quit();
if(!pre[x]&&!nex[y])num[pos[x]]--;
pre[x]=y;nex[y]=x;
}
ans=1;
for(int i=1;i<=n;i++)ans=ans*jc[num1[i]]%mod;
for(int i=1;i<=n;i++)ans=ans*jc[num[i]]%mod;
printf("%I64d\n",ans);
return 0;
}