测试地址:Function
题目大意: 给出一个关于
到
的置换
,一个关于
到
的置换
,求有多少从
到
映射到
到
的映射
,知足
。
作法: 本题须要用到思惟+组合数学。
根据题目的要求,
能够经过置换
成为
,因此咱们对于置换
画一个反向循环图(即,从点
能够走到点
,反向就是从点
走到点
),再对置换
画一个循环图,在两张图中分别选出两个点
,表明
,那么能够发现,当
走一步,
也走一步,
应该仍是成立的。这也就说明,
在
中的循环长度,应该是
在
中循环长度的因数,这样才能保证
在走的过程当中老是成立。而由于初始的
又有
种选择(
即
所在循环的长度),所以咱们找到了一种统计答案的方法:对一个
中的环,在
中找到全部环长为这个环长的因数的环,累加
。直接统计因数的贡献比较麻烦,咱们反过来考虑每一个
中的环,它对环长为
的倍数的环有
贡献,咱们只须要一开始算出
,表示环长为
的
中的环的个数,就能够
计算贡献了。那么对于
中的每一个环,能够计算出这个环的方案数,运用乘法原理把每一个环的方案数乘起来就好了。
我傻逼的地方:我又分不清楚
和
了…这错误一次比一次以为傻逼…
如下是本人代码:php
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1000000007; int n,m,a[100010],b[100010],tot; ll cnt[100010],tmp[100010]; bool vis[100010]; void find_loop(int *nxt,int v) { while(!vis[v]) { vis[v]=1;tot++; v=nxt[v]; } } int main() { int t=0; while(scanf("%d%d",&n,&m)!=EOF) { for(int i=0;i<n;i++) scanf("%d",&a[i]); for(int i=0;i<m;i++) scanf("%d",&b[i]); for(int i=0;i<=m;i++) tmp[i]=vis[i]=0; for(int i=0;i<m;i++) if (!vis[i]) { tot=0; find_loop(b,i); tmp[tot]++; } for(int i=1;i<=n;i++) cnt[i]=0; for(int i=1;i<=m;i++) for(int j=1;i*j<=n;j++) cnt[i*j]=(cnt[i*j]+tmp[i]*(ll)i)%mod; ll ans=1; for(int i=0;i<n;i++) vis[i]=0; for(int i=0;i<n;i++) if (!vis[i]) { tot=0; find_loop(a,i); ans=ans*cnt[tot]%mod; } printf("Case #%d: %lld\n",++t,ans); } return 0; }
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1000000007; int n,m,a[100010],b[100010],tot; ll cnt[100010],tmp[100010]; bool vis[100010]; void find_loop(int *nxt,int v) { while(!vis[v]) { vis[v]=1;tot++; v=nxt[v]; } } int main() { int t=0; while(scanf("%d%d",&n,&m)!=EOF) { for(int i=0;i<n;i++) scanf("%d",&a[i]); for(int i=0;i<m;i++) scanf("%d",&b[i]); for(int i=0;i<=m;i++) tmp[i]=vis[i]=0; for(int i=0;i<m;i++) if (!vis[i]) { tot=0; find_loop(b,i); tmp[tot]++; } for(int i=1;i<=n;i++) cnt[i]=0; for(int i=1;i<=m;i++) for(int j=1;i*j<=n;j++) cnt[i*j]=(cnt[i*j]+tmp[i]*(ll)i)%mod; ll ans=1; for(int i=0;i<n;i++) vis[i]=0; for(int i=0;i<n;i++) if (!vis[i]) { tot=0; find_loop(a,i); ans=ans*cnt[tot]%mod; } printf("Case #%d: %lld\n",++t,ans); } return 0; }