你須要構造一個排列c++
初始時\(p_i=i\),一次操做定義爲:spa
選擇一些\((x_i,y_i)\),知足每一個數字只能出現一次code
依次交換\(p_{x_i},p_{y_i}\)blog
定義一個排列 \(P\) 的最少交換次數爲\(f(P)\)it
如今 \(P\) 有 \(k\) 個位置的排列順序是未知的,定義某一種肯定順序的方案是\(P'\)io
求\(\sum f(P')\)class
\(1 \le n \le 10^6 \ , \ k \le min(12,n)\)im
首先操做次數不會超過2,考慮每個輪換static
考慮一個排列\(P\),它的貢獻是:
1.若是全部輪換的大小<=2 ,最少的步數爲0/1,貢獻爲0img
2.若是存在輪換的大小>2,最少的步數爲2,考慮貢獻
大小不一樣的輪換不會互相影響
大小相同的輪換能夠兩兩拼在一塊兒,也能夠單獨存在
寫成dp即$h_{i,j} = h_{i,j-1}i + h_{i,j-2}(j-1)i $
若是大小爲\(i\)的輪換有\(m_i\)個,總貢獻爲\(\prod h_{i,m_i}\)
若是肯定的點指向不肯定的點存在一條鏈\(l\),那麼就把不肯定的點的大小看作\(|l|+1\)
預處理出全部的\(h\),這樣就能夠只考慮不肯定的點的排列
因爲貢獻只和輪換的大小有關,能夠枚舉集合劃分再把貢獻乘以一個圓排列
時間複雜度\(O(n \ log \ n + bell(k) \ k)\)
#include<bits/stdc++.h> #define pb push_back using namespace std; const int N=1000010,mod=1e9+7; int n,k,p[N],q[N],cnt[N],pos[N],a[N],b[N],c[N],bl[N],iv[N],vis[N],T,preans,precnt[N],ans,fac[N],prefg1,prefg2,Bell; vector<int>h[N]; void inc(int&x,int y){x+=y;if(x>=mod)x-=mod;} int pw(int x,int y){ int re=1; for(;y;y>>=1,x=1ll*x*x%mod) if(y&1)re=1ll*re*x%mod; return re; } void pre(){ for(int i=fac[0]=1;i<=n;++i){ fac[i]=1ll*fac[i-1]*i%mod; int lim=n/i; h[i].pb(1);h[i].pb(i); for(int j=2;j<=lim;++j){ h[i].pb((h[i][j-1]+1ll*h[i][j-2]*(j-1)%mod)*i%mod); } } } void calc(int tot){ static int st[N],tp; ++T;tp=0; for(int i=1;i<=tot;++i)b[i]=0,c[i]=0; for(int i=1;i<=k;++i)b[bl[i]]++,c[bl[i]]+=a[i]; int re=1,fg1=prefg1,fg2=prefg2; for(int i=1;i<=tot;++i){ re=1ll*re*fac[b[i]-1]%mod; cnt[c[i]]++;fg1|=c[i]>1;fg2|=c[i]>2; if(vis[c[i]]!=T)vis[c[i]]=T,st[++tp]=c[i]; } if(!fg1)re=1; if(fg2)re=1ll*re*preans%mod; for(int i=1;i<=tp;++i){ int x=st[i]; if(fg2)re=1ll*re*iv[x]%mod*h[x][cnt[x]]%mod; cnt[x]=precnt[x]; } inc(ans,re); } void dfs(int x,int y){ if(x==k+1){calc(y);return;} for(int i=1;i<=y+1;++i){ bl[x]=i; dfs(x+1,max(i,y)); } } int main(){ freopen("determination.in","r",stdin); freopen("determination.out","w",stdout); scanf("%d%d",&n,&k);k=0; for(int i=1;i<=n;++i){ scanf("%d",&p[i]); if(p[i])q[p[i]]=i;else pos[++k]=i; } for(int i=1;i<=k;++i){ int len=1;vis[pos[i]]=1; for(int j=q[pos[i]];j;j=q[j])vis[j]=1,len++; a[i]=len; } for(int i=1;i<=n;++i)if(!vis[i]){ int len=1;vis[i]=1; for(int j=p[i];j!=i;j=p[j])vis[j]=1,len++; cnt[len]++;prefg2|=len>2;prefg1|=len>1; } pre(); preans=1; for(int i=1;i<=n;++i){ precnt[i]=cnt[i]; preans=1ll*preans*h[i][cnt[i]]%mod; iv[i]=pw(h[i][cnt[i]],mod-2); vis[i]=0; } dfs(1,0); cout<<ans<<endl; return 0; }