CF698F Coprime Permutation 题解
题意
给定一个未填满的数组 ,求有多少种 的排列 满足对于任意 ,都有 ,答案对 取模。
题解
部分参考这篇题解(感觉这篇题解应该是目前为止最详细的吧)。
记 为 中所有素数与 构成的集合, 为所有在 中出现过的质因子的乘积()。
由于 中任意两数 互质,故 ,从而 。
因此,记 ,根据 中质因子的个数可分析出 是 的一个排列。
进一步对于合数 , 。
因此,如果 中数对应的 值确定了,那么所有数的 值也就都确定了。
先考虑所有 都为 的情况。定义 ,那么 ,于是对于质数 , 的一个条件为 (),同时可知 时 。
确定完所有数的 值后,如果对于 有 ,那么 是等价的,于是 在 中的位置可以任意交换。
根据上述推导,可以发现如果设 表示有多少个质数 满足 , 表示有多少个数的 值等于 ,那么答案即为 。
如果位置 的 有值,首先要判断该位置上填的值是否合法。设 为 中不超过 的质因子的乘积,则 等于 的大于 的质因子或 (没有大于 的质因子),不合法的情况有以下三种:
-
。注意由 可以推出对于所有不超过 的质数 ,,所以 和 不超过 的质因子应该相同。
-
。因为可以推出 的不同质因子个数和 的不同质因子个数相同,并且大于 的质因子至多只有一个,所以要么 和 同时没有大于 的质因子,要么同时有大于 的质因子、且根据 可知 。
-
无法构成一一映射,即存在不同的 使得 。前者为 后者为 是说 中存在某个位置 (其中 ,), 要等于 个不同的值;前者为 后者为 是说 中存在某两个位置 (其中 ,), 要等于 个相同的值。
如果合法,只需修改对应位置的 和 的值即可。注意最后一步中 或 时要做一些特判,但大体思路相同。总时间复杂度 。
Code
#include<bits/stdc++.h>
#define LL long long
#define mod 1000000007
using namespace std;
int n,p_t=0;
LL ans=1;
int a[1000002],p[1000002],t[1000002],t1[1000002],cnt[1000002],cnt2[1000002],to[1000002];
LL fac[1000002];
bool u[1000002];
inline void init()
{
for(int i=fac[0]=cnt2[1]=1;i<=n;++i)t[i]=t1[i]=1,fac[i]=(fac[i-1]*i)%mod;
t[1]=n;
for(int i=2;i<=n;++i)
{
if(!u[i])
{
++cnt2[n/(p[++p_t]=i)];
for(int j=i;j<=n;j+=i)t[j]*=i;
if(i<=n/i)for(int j=i;j<=n;j+=i)t1[j]*=i;
}
for(int j=1;p[j]*i<=n;++j)
{
u[p[j]*i]=1;
if(!(i%p[j]))break;
}
}
for(int i=2;i<=n;++i)++cnt[t[i]];
}
int main()
{
scanf("%d",&n),init();
for(int i=1,x;i<=n;++i)
{
scanf("%d",&a[i]);
if(a[i])
{
x=t[a[i]]/t1[a[i]];
if((t1[a[i]]^t1[i]) || ((n/x)^(n/(t[i]/t1[i]))))return 0&puts("0");
if(a[i]>1)--cnt[t[a[i]]];
if(a[i]==1)--cnt2[1];
else if(x>n/x)
{
if(!to[x])to[x]=t[i]/t1[i],--cnt2[n/x];
else if(to[x]^(t[i]/t1[i]))return 0&puts("0");
}
}
}
for(int i=1;i<=n;++i)(((ans*=fac[cnt[i]])%=mod)*=fac[cnt2[i]])%=mod;
return 0&printf("%lld",ans);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端