1436 方程的解数

51nod网站

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1436




这道题的方法很简单,关键在于这道题有很多角度都能切入思考,能不能快速想到合适的解法。


方法步骤:

将k化为二进制,则对应bit位置若为0,则a1,a2,...,an相应的bit位设为b1,b2,...,bn。相邻2个bi不能同时为1。考虑这样情况的总数。

既然不能出现连续的1。设方法总数为f(n),bn为1时,b(n-1)为0,此时方法数为f(n-2)。当bn为0时,方法数为f(n-1)。

则利用数学归纳法,很容易得到:f(n) = f(n-1)+f(n-2)。初始条件可令f(0)=1,f(1)=2,从而有f(2)=3。

        最终答案

其中count为k数字二进制里1的数量。

最终求解的时候,f(n)可以用矩阵快速幂log(n)求解,并且可以发现是菲波拉契数列。并且所有涉及到的幂次方都可以用快速幂进行求解。


       最后要注意:

        1.取余要注意最后结果是负数的话要变为正数

2.当2^l-1比k小的时候,方案数为0。


#include <stdio.h>


__int64 n, k, tmp, l, m, myresult, tmp1, mycount, fn, mymaxsize;

#define mymaxsize1 9223372036854775807  //2^63-1


void MyMultiply(__int64 A[2][2], __int64 B[2][2], __int64 C[2][2])
{
	int i, j;
	__int64 result[2][2], tmp;

	result[0][0] = result[0][1] = result[1][0] = result[1][1] = 0;

	for (i = 0; i < 2; ++i)
	{
		for (k = 0; k < 2; ++k)
		{
			tmp = A[i][k];
			for (j = 0; j < 2; ++j)
			{
				result[i][j] = (result[i][j] + (tmp * B[k][j]) % m) % m;
			//	result[i][j] = result[i][j] + (A[i][k] * B[k][j]);
			}
		}
	}


	for (i = 0; i < 2; ++i)
	{
		for (j = 0; j < 2; ++j)
		{
			C[i][j] = result[i][j];
		}
	}
}

void GetMyPowerMod(__int64 x, __int64 y, __int64 m, __int64 &result)
{
	result = 1;
	__int64 tmp1=x;
	while (y)
	{
		if (y & 1) { result = (result * tmp1) % m; }
		y >>= 1;
		tmp1 = (tmp1 * tmp1) % m;
	}
}

void Bit1Count(__int64 x, __int64 &result)
{
	result = 0;
	for (result = 0; x; ++result)
	{
		x &= (x - 1);
	}
}

void GetFib(__int64 n, __int64 &result)
{
	n += 2;
	__int64 resultarray[2][2], C[2][2];
	resultarray[0][0] = resultarray[1][1] = 1;
	resultarray[0][1] = resultarray[1][0] = 0;
	C[0][1] = C[1][1] = C[1][0] = 1; C[0][0] = 0;

	while (n)
	{
		if (n & 1) 
		{ 
			MyMultiply(resultarray, C, resultarray);
		}
		n >>= 1;
		MyMultiply(C, C, C);
	}

	result = resultarray[0][1];
}


int main()
{
	scanf("%lld%lld%lld%lld", &n, &k, &l, &m);

	if (l < 63)
	{ 
		GetMyPowerMod(2, l, mymaxsize1, tmp1);
		if (tmp1<=k)
		{
			printf("0");
			return 0;
		}
	}
	

	Bit1Count(k, mycount);

	GetFib(n, fn);
	GetMyPowerMod(2, n, m, tmp1);
	GetMyPowerMod(tmp1 - fn, mycount, m, myresult);
	GetMyPowerMod(fn, l - mycount, m, tmp);
	myresult = (myresult * tmp) % m;

	if (myresult<0)
	{
		myresult += m;
	}
	printf("%lld", myresult);
	for (int i = 1; i <= 10; ++i)
	{
		scanf("%lld", &n);
	}

	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值