BZOJ 3113: Toy

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值