这题时限不知道怎么搞的,我的代码跑了4000+MS A掉了,可是时限是4S
然后做法什么的不是很懂,好像很玄学的样子,具体看08年的论文。
大概是利用划分对置换进行分类,每一类的循环节个数是一样的,这样统计出每一类的置换个数,然后就可做了。
代码好短……
#include<iostream> #include<cstdio> #include<cstring> using namespace std; typedef long long ll; ll p; ll qmul(ll a,ll b){ ll ans=1; for(;b;b>>=1,a=a*a%p)if(b&1)ans=ans*a%p; return ans; } ll inv(ll x){ return qmul(x,p-2); } ll gcd(ll a,ll b){ return b?gcd(b,a%b):a; } ll ans,l[60],tot,m,n; ll f(){ ll ans=0; for(int i=1;i<=tot;i++){ ans+=l[i]/2; for(int j=i+1;j<=tot;j++) ans+=gcd(l[i],l[j]); } return ans%(p-1); } void dfs(int last,int k,int n,ll s){ l[++tot]=n; int t=s*inv(n)%p; if(n==last)t=t*inv(k+1)%p; else t=t*inv(1)%p; ans=(ans+t*qmul(m,f())%p)%p; tot--; for(int j=last;j<=n-j;j++){ l[++tot]=j; int t=s*inv(j)%p; if(j==last)dfs(j,k+1,n-j,t*inv(k+1)%p); else dfs(j,1,n-j,t*inv(1)%p); tot--; } } int main(){ //freopen("a.in","r",stdin); scanf("%lld%lld%lld",&n,&m,&p); ll s=1; for(int i=1;i<=n;i++)s=s*i%p; dfs(1,0,n,s); for(int i=1;i<=n;i++)ans=ans*inv(i)%p; printf("%d\n",ans); return 0; }