[bzoj4833][数论][min-max容斥]最小公倍佩尔数

本文探讨了一种特定的数列求和问题,在模P意义下计算序列的和,利用数学归纳法推导出数列的递推公式,并通过编程实现高效的计算方法。文章详细解析了数列的性质,提供了完整的代码实现。

Description

令(1+sqrt(2))n=e(n)+f(n)*sqrt(2),其中e(n),f(n)都是整数,显然有(1-sqrt(2))n=e(n)-f(n)*sqrt(2)。令g(

n)表示f(1),f(2)…f(n)的最小公倍数,给定两个正整数n和p,其中p是质数,并且保证f(1),f(2)…f(n)在模p意义
下均不为0,请计算sigma(i*g(i)),1<=i<=n.其在模p的值。

Input

第一行包含一个正整数 T ,表示有 T 组数据,满足 T≤210 。接下来是测试数据。每组测试数据只占一行,包含 两个正整数 n 和 p
,满足 1≤n≤106,2≤p≤109+7 。保证所有测试数据的 n 之和不超过 3×10^6 。

Output

对于每组测试数据,输出一行一个非负整数,表示这组数据的答案。

Sample Input

5

1 233

2 233

3 233

4 233

5 233

Sample Output

1

5

35

42

121

题解

推一下式子
会有 e ( n + 1 ) = e ( n ) + 2 ∗ f ( n ) e(n+1)=e(n)+2*f(n) e(n+1)=e(n)+2f(n), f ( n + 1 ) = e ( n ) + f ( n ) f(n+1)=e(n)+f(n) f(n+1)=e(n)+f(n)
所以 e ( n + 1 ) = f ( n ) + f ( n + 1 ) e(n+1)=f(n)+f(n+1) e(n+1)=f(n)+f(n+1)
所以 f ( n + 1 ) = 2 ∗ f ( n ) + f ( n − 1 ) f(n+1)=2*f(n)+f(n-1) f(n+1)=2f(n)+f(n1)
类似斐波那契数列的式子,结论有一个是形如 f ( n + 1 ) = a ∗ f ( n ) + b ∗ f ( n − 1 ) f(n+1)=a*f(n)+b*f(n-1) f(n+1)=af(n)+bf(n1)的式子均满足 g c d ( f ( a ) , f ( b ) ) = f ( g c d ( a , b ) ) gcd(f(a),f(b))=f(gcd(a,b)) gcd(f(a),f(b))=f(gcd(a,b))
那么接下来就和51nod1355是一样的了
感觉直接抄上去就能过啊…

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#include<set>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
using namespace std;
inline int read()
{
	int f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int stack[20];
inline void write(LL x)
{
	if(x<0){putchar('-');x=-x;}
    if(!x){putchar('0');return;}
    int top=0;
    while(x)stack[++top]=x%10,x/=10;
    while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(LL x){write(x);putchar('\n');}
const int MAXN=3000005;
LL f[MAXN],g[MAXN],ans,mod;
LL pow_mod(LL a,LL b)
{
	LL ret=1;
	while(b)
	{
		if(b&1)ret=ret*a%mod;
		a=a*a%mod;b>>=1;
	}
	return ret;
}
int n;
int main()
{
	int T=read();while(T--)
	{
		n=read();mod=read();
		f[1]=g[1]=1;
		for(int i=2;i<=n;i++)f[i]=g[i]=(2*f[i-1]+f[i-2])%mod;
		for(int i=1;i<=n;i++)
		{
			LL inv=pow_mod(g[i],mod-2);
			for(int j=2;i*j<=n;j++)g[i*j]=g[i*j]*inv%mod;
		}
		ans=0;LL temp=1;
		for(int i=1;i<=n;i++)
		{
			temp=temp*g[i]%mod;
			ans=(ans+temp*i)%mod;
		}
		pr2(ans);
	}
	return 0;
}

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值