BZOJ 3113: Toy

来源:互联网 发布:花溪区4g网络基站建设 编辑:程序博客网 时间:2024/06/05 08:58

Description

外面有一圈N个结点,中心有一个结点与N个结点都相连,总共就是2*N条边,删除N条边,使N+1个点连通,旋转相同视为等价,问有多少种情况。

Input

输入N,M

3<=N<=10^9, 2<=M<=10^9

Output

输出方案数 Mod M的结果

Sample Input

3 10000
4 10000
4 10


Sample Output

6
13
3


先打个表:1,3,6,13,25,58,然后放到oeis里
然后得到这个公式:1/nSum_{d divides n} phi(n/d)A004146(d)
A004146的公式是这样:a(n+1) = 3*a(n) - a(n-1) + 2.
于是直接根号n枚举d,然后根号d求phi,矩阵快速幂求A004146


代码:

#include<bits/stdc++.h>typedef long long ll;typedef long double ldb;ll mod;inline ll fm(ll x,ll y){ll tmp=(x*y-(ll)((ldb)x/mod*y+1e-8)*mod);return tmp<0?tmp+mod:tmp;}inline void mul(ll (&a)[3][3],ll (&b)[3][3],ll (&c)[3][3]){ll t[3][3]={{0,0,0},{0,0,0},{0,0,0}};for(int i=0;i<3;i++)for(int j=0;j<3;j++)for(int k=0;k<3;k++)t[i][k]+=fm(a[i][j],b[j][k]);for(int i=0;i<3;i++)for(int j=0;j<3;j++)c[i][j]=t[i][j]%mod;}inline ll f(int x){if(x<=1)return x;x--;ll a[3][3]={{1,0,2},{0,0,mod-1},{0,1,3}},b[3][3]={{1,0,0},{0,1,0},{0,0,1}};for(int i=1;i<=x;i<<=1){if(i&x)mul(b,a,b);mul(a,a,a);}ll ret=b[0][2]+b[2][2];if(ret>=mod)return ret-mod;return ret;}inline int phi(int x){int t=x;for(int i=2;i*i<=x;i++)if(x%i==0){t/=i,t*=i-1;x/=i;while(x%i==0)x/=i;}if(x>1)t/=x,t*=x-1;return t;}int main(){int n;while(~scanf("%d%lld",&n,&mod)){mod*=n;ll a2=0;for(int i=1;i*i<=n;i++)if(n%i==0){if(i*i==n){a2+=fm(phi(i),f(i));}else{a2+=fm(phi(i),f(n/i))+fm(phi(n/i),f(i));}a2%=mod;}printf("%lld\n",a2/n);}}

link to my blog


0 0