【HDU5950 2016ACM ICPC亚洲区沈阳站-重现赛 C】【矩阵快速幂】Recursive sequence 矩阵递推 i ^ 4

Recursive sequence

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 132    Accepted Submission(s): 84


Problem Description
Farmer John likes to play mathematics games with his N cows. Recently, they are attracted by recursive sequences. In each turn, the cows would stand in a line, while John writes two positive numbers a and b on a blackboard. And then, the cows would say their identity number one by one. The first cow says the first number a and the second says the second number b. After that, the i-th cow says the sum of twice the (i-2)-th number, the (i-1)-th number, and   i4 . Now, you need to write a program to calculate the number of the N-th cow in order to check if John’s cows can make it right.  
 

Input
The first line of input contains an integer t, the number of test cases. t test cases follow.
Each case contains only one line with three numbers N, a and b where N,a,b <   231  as described above.
 

Output
For each test case, output the number of the N-th cow. This number might be very large, so you need to output it modulo 2147493647.
 

Sample Input
  
  
2 3 1 2 4 1 10
 

Sample Output
  
  
85 369
Hint
In the first case, the third number is 85 = 2*1十2十3^4. In the second case, the third number is 93 = 2*1十1*10十3^4 and the fourth number is 369 = 2 * 10 十 93 十 4^4.
 

Source
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const UI Z = 2147493647;
const int G = 7;
struct MX
{
	UI v[G][G];
	void O() { MS(v, 0); }
	void E() { MS(v, 0); for (int i = 0; i < G; ++i)v[i][i] = 1; }
	void P()
	{
		for (int i = 0; i < G; ++i)
		{
			for (int j = 0; j < G; ++j)printf("%u ", v[i][j]); puts("");
		}
	}
	MX operator * (const MX &b) const
	{
		MX c; c.O();
		for (int i = 0; i < G; ++i)
		{
			for (int j = 0; j < G; ++j)
			{
				for (int k = 0; k < G; ++k)
				{
					c.v[i][j] = (c.v[i][j] + (UL)v[i][k] * b.v[k][j]) % Z;
				}
			}
		}
		return c;
	}
	MX operator + (const MX &b) const
	{
		MX c; c.O();
		for (int i = 0; i < G; ++i)
		{
			for (int j = 0; j < G; ++j)
			{
				c.v[i][j] = (v[i][j] + b.v[i][j]) % Z;
			}
		}
		return c;
	}
	MX operator ^ (LL p) const
	{
		MX y; y.E();
		MX x; memcpy(x.v, v, sizeof(v));
		while (p)
		{
			if (p & 1)y = y * x;
			x = x * x;
			p >>= 1;
		}
		return y;
	}
}a, b;
int casenum, casei;
int getpow(int n, int K)
{
	a.O(); b.O();
	for (int i = 0; i <= K; ++i)a.v[0][i] = 1;
	for (int i = 0; i <= K; ++i)b.v[0][i] = 1;
	for (int i = 1; i <= K; ++i)
	{
		for (int j = i; j <= K; ++j)
		{
			b.v[i][j] = (b.v[i - 1][j - 1] + b.v[i][j - 1]) % Z;
		}
	}
	a = a * (b ^ (n - 1));
	return a.v[0][K];
}
int main()
{
	scanf("%d", &casenum);
	for (casei = 1; casei <= casenum; ++casei)
	{
		int n, aa, bb;
		scanf("%d%d%d", &n, &aa, &bb);
		/*
		b.v[0] = { 0,2,0,0,0,0,0 };
		b.v[1] = { 1,1,0,0,0,0,0 };
		b.v[2] = { 0,1,1,1,1,1,1 };
		b.v[3] = { 0,4,0,1,2,3,4 };
		b.v[4] = { 0,6,0,0,1,3,6 };
		b.v[5] = { 0,4,0,0,0,1,4 };
		b.v[6] = { 0,1,0,0,0,0,1 };
		*/
		a.v[0][0] = aa; a.v[0][1] = bb; a.v[0][2] = 1; a.v[0][3] = 2; a.v[0][4] = 4; a.v[0][5] = 8; a.v[0][6] = 16;

		b.v[0][0] = 0; b.v[0][1] = 2; b.v[0][2] = 0; b.v[0][3] = 0; b.v[0][4] = 0; b.v[0][5] = 0; b.v[0][6] = 0;
		b.v[1][0] = 1; b.v[1][1] = 1; b.v[1][2] = 0; b.v[1][3] = 0; b.v[1][4] = 0; b.v[1][5] = 0; b.v[1][6] = 0;
		b.v[2][0] = 0; b.v[2][1] = 1; b.v[2][2] = 1; b.v[2][3] = 1; b.v[2][4] = 1; b.v[2][5] = 1; b.v[2][6] = 1;
		b.v[3][0] = 0; b.v[3][1] = 4; b.v[3][2] = 0; b.v[3][3] = 1; b.v[3][4] = 2; b.v[3][5] = 3; b.v[3][6] = 4;
		b.v[4][0] = 0; b.v[4][1] = 6; b.v[4][2] = 0; b.v[4][3] = 0; b.v[4][4] = 1; b.v[4][5] = 3; b.v[4][6] = 6;
		b.v[5][0] = 0; b.v[5][1] = 4; b.v[5][2] = 0; b.v[5][3] = 0; b.v[5][4] = 0; b.v[5][5] = 1; b.v[5][6] = 4;
		b.v[6][0] = 0; b.v[6][1] = 1; b.v[6][2] = 0; b.v[6][3] = 0; b.v[6][4] = 0; b.v[6][5] = 0; b.v[6][6] = 1;
		if (n == 1)printf("%d\n", aa);
		else
		{
			a = a * (b ^ (n - 2));
			printf("%u\n", a.v[0][1]);
		}
	}
	return 0;
}
/*
【题意】
f[1] = a;
f[2] = b;
f[i] = 2 * f[i - 2] + f[i - 1] + i ^ 4;
求f[n]

【分析】
如果我们需要使用到i ^ k,其只能由 (i - 1) ^ k转移而来。手动化简,得到——
(i)^4 - (i-1)^4 = 4*(i)^3 - 6*(i)^2 + 4*(i)^1 - 1;
(i)^3 - (i-1)^3 = 3*(i)^2 - 3*(i)^1 + 1;
(i)^2 - (i-1)^2 = 2*(i)^1 - 1;
(i)^1 - (i-1)^1 = 1;
a.v[0] = { 0,a,b,2,4,8,16};
b.v[0] = { 0,2,0,0,0,0,0 };
b.v[1] = { 1,1,0,0,0,0,0 };
b.v[2] = { 0,1,1,1,1,1,1 };
b.v[3] = { 0,4,0,1,2,3,4 };
b.v[4] = { 0,6,0,0,1,3,6 };
b.v[5] = { 0,4,0,0,0,1,4 };
b.v[6] = { 0,1,0,0,0,0,1 };
拓展——
如何得到n ^ k 呢? 发现其矩阵的展开类似于二项式展开。getpow(n, K) 就是 n ^ K;
int getpow(int n, int K)
{
	a.O(); b.O();
	for (int i = 0; i <= K; ++i)a.v[0][i] = 1;
	for (int i = 0; i <= K; ++i)b.v[0][i] = 1;
	for (int i = 1; i <= K; ++i)
	{
		for (int j = i; j <= K; ++j)
		{
			b.v[i][j] = (b.v[i - 1][j - 1] + b.v[i][j - 1]) % Z;
		}
	}
	a = a * (b ^ (n - 1));
	return a.v[0][K];
}

【时间复杂度&&优化】
O(7 ^ 3 * log(n))

【数据】
2
3 1 2
4 1 10

*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值