Two positive integers are coprime if and only if they don't have a common divisor greater than 1.
Some bear doesn't want to tell Radewoosh how to solve some algorithmic problem. So, Radewoosh is going to break into that bear's safe with solutions. To pass through the door, he must enter a permutation of numbers 1 through n. The door opens if and only if an entered permutation p1, p2, ..., pn satisfies:
In other words, two different elements are coprime if and only if their indices are coprime.
Some elements of a permutation may be already fixed. In how many ways can Radewoosh fill the remaining gaps so that the door will open? Print the answer modulo 109 + 7.
The first line of the input contains one integer n (2 ≤ n ≤ 1 000 000).
The second line contains n integers p1, p2, ..., pn (0 ≤ pi ≤ n) where pi = 0 means a gap to fill, and pi ≥ 1 means a fixed number.
It's guaranteed that if i ≠ j and pi, pj ≥ 1 then pi ≠ pj.
Print the number of ways to fill the gaps modulo 109 + 7 (i.e. modulo 1000000007).
4 0 0 0 0
4
5 0 0 1 2 0
2
6 0 0 1 2 0 0
0
5 5 3 4 2 1
0
In the first sample test, none of four element is fixed. There are four permutations satisfying the given conditions: (1,2,3,4), (1,4,3,2), (3,2,1,4), (3,4,1,2).
In the second sample test, there must be p3 = 1 and p4 = 2. The two permutations satisfying the conditions are: (3,4,1,2,5), (5,4,1,2,3).
题意:构造一个1到n的排列 a1,a2,......an a1,a2,......an 满足对于任意i,j满足 1<=i<j<=n 1<=i<j<=n ai,aj 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 pres[N],nex[N];
vector<int>v[N]; //每个数包含的质因数
void quit(){puts("0");exit(0);}
int main()
{
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; //mul[j]表示包含有j的所有质因数的最小的数
}
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(pres[x]&&pres[x]!=y)quit(); //
if(nex[y]&&nex[y]!=x)quit();
if(!pres[x]&&!nex[y])num[pos[x]]--; //
pres[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;
}
以上内容参考自:https://blog.csdn.net/make_it_for_good/article/details/52301021
侵删