測試地址: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; }