矩阵快速幂2Jzzhu and Sequences Recurrences Contemplation! Algebra Reading comprehension

来!接着写题解,立个flag:矩阵快速幂题解不写完今晚不睡觉!

此题解是接着矩阵快速幂1写的,此篇有哪里写不清楚的地方导致看不懂的可以先看1:https://blog.csdn.net/qq_45364953/article/details/99705663

目录

来!接着写题解,立个flag:矩阵快速幂题解不写完今晚不睡觉!

Jzzhu and Sequences

Recurrences

Contemplation! Algebra

Reading comprehension


问题四:

Jzzhu and Sequences

CodeForces - 450B

Jzzhu has invented a kind of sequences, they meet the following property:

You are given x and y, please calculate fn modulo 1000000007 (109 + 7).

Input

The first line contains two integers x and y (|x|, |y| ≤ 109). The second line contains a single integer n (1 ≤ n ≤ 2·109).

Output

Output a single integer representing fn modulo 1000000007 (109 + 7).

Examples

Input

2 3
3

Output

1

Input

0 -1
2

Output

1000000006

Note

In the first sample, f2 = f1 + f3, 3 = 2 + f3, f3 = 1.

In the second sample, f2 =  - 1;  - 1 modulo (109 + 7) equals (109 + 6).


题意:给出f1,f2,求fn。

分析:和斐波那契数列一样,把转移矩阵换一下,f1,f2换一下就行。不过此题不用那么复杂可以发现这个数列的fn最后一位是有周期的,多写几个f 就发现了T=6,然后根据周期就可以“投机取巧”(说白了是自己太懒不想学矩阵,我能怎么办自己太菜)的把fn转换成输出f0到f5之间的哪个数了,很明显这个数是n➗6的余数即n%6。

代码:

#include<iostream>
using namespace std;
int main() {
	long long int f[6], ans = 0, ans1 = 0, ans2 = 0, n = 0, k = 0,mod=1000000007;
	cin >> ans1 >> ans2;
	cin >> n;
	f[1] = ans1 % mod;
	f[2] = ans2 % mod;
	f[3] = (ans2 - ans1 )% mod;
	f[4] = (f[3] - ans2 )% mod;
	f[5] = (f[4] - f[3] )% mod;
	f[0] = (f[5] - f[4] )% mod;
	cout << (f[n % 6] + mod) % mod; //+mod很重要
	return 0;
}

正经做法呢?代码:

#include<iostream>
#include<cstring>
#include<vector>
#include<cmath>
using namespace std;
typedef long long ll;
struct matrix
{
	ll mat[2][2];
	matrix() {
		memset(mat, 0, sizeof(mat));
	}
}U, F;
ll mod;
matrix mul(matrix Q, matrix A)
{
	matrix C;
	for (int i = 0; i < 2; i++)
		for (int j = 0; j < 2; j++)
			for (int k = 0; k < 2; k++)
				C.mat[i][j] = (C.mat[i][j] + A.mat[i][k] * Q.mat[k][j]%mod)%mod;
	return C;
}
matrix powmul(matrix A, ll m)
{
	matrix ans = F;
	while (m > 0)
	{
		if (m & 1)
			ans = mul(ans, A);
		A = mul(A, A);
		m >>= 1;
	}
	return ans;
}
int main() {
	mod = 1000000007;
	ll a, b, n;
	cin >> a >> b;
	cin >> n;
		if (n == 1)
			cout << a << endl;
		else {
			U.mat[0][0] = 1; U.mat[0][1] = -1;
			U.mat[1][0] = 1; U.mat[1][1] = 0;

			F.mat[0][0] = b; F.mat[0][1] = 0;
			F.mat[1][0] = a; F.mat[1][1] = 0;
			matrix ans = powmul(U, n-1);
			cout << (ans.mat[1][0]+mod) %mod<< endl;
		}
	return 0;
}

问题五:

Recurrences

UVA - 10870

Consider recurrent functions of the following form:

f(n) = a1f(n−1) + a2f(n−2) + a3f(n−3) + ... + adf(n−d), for n > d,

where a1, a2, ..., ad are arbitrary constants.

A famous example is the Fibonacci sequence, defined as: f(1) = 1, f(2) = 1, f(n) = f(n−1) +f (n−2). Here d = 2, a1 = 1, a2 = 1. Every such function is completely described by specifying d (which is called the order of recurrence), values of d coefficients: a1, a2, ..., ad, and values of f(1), f(2), ..., f(d). You’ll be given these numbers, and two integers n and m. Your program’s job is to compute f(n) modulo m.
Input
Input file contains several test cases. Each test case begins with three integers: d, n, m, followed by two sets of d non-negative integers. The first set contains coefficients: a1, a2, ..., ad. The second set gives values of f(1), f(2), ..., f(d). You can assume that: 1 ≤ d ≤ 15, 1 ≤ n ≤ 231 −1, 1 ≤ m ≤ 46340. All numbers in the input will fit in signed 32-bit integer. Input is terminated by line containing three zeroes instead of d, n, m. Two consecutive test cases are separated by a blank line.
Output
For each test case, print the value of f(n)( mod m) on a separate line. It must be a non-negative integer, less than m.
Sample Input
1 1 100   //d n m

2  //系数a1

1   //fn的值

                           //这里有一个空行
2 10 100

1 1

1 1


3 2147483647 12345

12345678 0 12345

1 2 3


0 0 0
Sample Output
1

55

423


题意:给出了递推式告诉你f(1),f(2),,,到f(d)的值以及递推式每项的系数求f(n)

和斐波那契数列差不多吧,变复杂了,增加了递推式的系数和项数,细节要好好注意。

举例,d=5的矩阵关系式为:
                |a1 a2 a3 a4 a5|      |   f[n]  |      | f[n+1]|  
                |1   0    0   0   0 |      | f[n-1] |      |   f[n]  |  
                |0   1    0   0   0 |  *   | f[n-2] | =  | f[n-1] |
                |0   0    1   0   0 |      | f[n-3] |      | f[n-2] |
                |0   0    0   1   0 |      | f[n-4] |      | f[n-3] |

代码:

#include<iostream>
#include<cstring>
#include<vector>
#include<cmath>
using namespace std;
typedef long long ll;
struct matrix
{
	ll mat[15][15];
	matrix() {
		memset(mat, 0, sizeof(mat));
	}
}U, F;
ll mod;
int d;
matrix mul(matrix Q, matrix A)
{
	matrix C;
	for (int i = 0; i < d; i++)
		for (int j = 0; j < d; j++)
			for (int k = 0; k < d; k++)
				C.mat[i][j] = (C.mat[i][j] + (A.mat[i][k] * Q.mat[k][j]) % mod) % mod;
	return C;
}
matrix powmul(matrix A, int m)
{
	matrix ans = F;
	while (m > 0)
	{
		if (m & 1)
			ans = mul(ans, A);
		A = mul(A, A);
		m >>= 1;
	}
	return ans;
}
int main() {

		ll n;
		while (cin >> d >> n >> mod) 
		{
			if (d == 0 && n == 0 && mod == 0)
				break;
			for (int i = 0; i < d; i++)
				cin >> U.mat[0][i]; //转移矩阵的第一行是递推式系数a1,a2,a3...
			for (int i = 1, j = 0; i < d; i++, j++)
				U.mat[i][j] = 1; //对角线向下平移一格全是1,其他为零
			for (int i = d - 1; i >= 0; i--)
				cin >> F.mat[i][0];   //倒着输入,f1在最下面
			if (n <=d)
				cout << F.mat[d - n][0]%mod<<endl;
			else {
				if (d == 1) {
					matrix ans0 = powmul(U, n - 1);
					cout << ans0.mat[0][0] << endl;
				}
				else {
					matrix ans = powmul(U, n - d + 1); 
                                  //注意这里为什么是n-d+1,矩阵最开始有了fd,再乘转移矩阵得到的fn肯定是fd,fd+1...之类的。
                                 //乘n-d次方得到的是f(d+n-d)=fn,在ans.mat[0][0]里面;乘n-d+1次方fn就在ans.mat[1][0]里面
					cout << ans.mat[1][0] << endl;
				}
			}
			getchar();
		}
	return 0;
}

总结:细节决定成败啊!无论什么时候输出总要模上mod,转移矩阵究竟要乘多少次?转移方程怎么写?

 问题六:

Contemplation! Algebra

UVA - 10655

Given the value of a+b and ab you will have to find the value of an + bn
Input
The input file contains several lines of inputs. Each line except the last line contains 3 non-negative integers p, q and n. Here p denotes the value of a+b and q denotes the value of ab. Input is terminated by a line containing only two zeroes. This line should not be processed. Each number in the input file fits in a signed 32-bit integer. There will be no such input so that you have to find the value of 00.
Output
For each line of input except the last one produce one line of output. This line contains the value of an + bn. You can always assume that an + bn fits in a signed 64-bit integer.
Sample Input
10 16 2

7 12 3

0 0
Sample Output
68

91


题意: 告诉a+b,ab的值,给一个n,求a^{n}+b^{n}

分析:\\n=0\ ans0=a^{0}+b^{0}=2\\ n=1\ ans1=a^{1}+b^{1}=a+b\\ n=2\ ans2=a^{2}+b^{2}=(a+b)*ans1-ab*ans0\\ n=3\ ans3=a^{3}+b^{3}=(a+b)*ans2-ab*ans1\\ \therefore ans(n)=(a+b)*ans(n-1)-ab*ans(n-2)写出矩阵:

#include<iostream>
#include<cstring>
#include<vector>
#include<cmath>
using namespace std;
typedef long long ll;
struct matrix
{
	ll mat[2][2];
	matrix() {
		memset(mat, 0, sizeof(mat));
	}
}U, F;
ll mod;
matrix mul(matrix Q, matrix A)
{
	matrix C;
	for (int i = 0; i < 2; i++)
		for (int j = 0; j < 2; j++)
			for (int k = 0; k < 2; k++)
				C.mat[i][j] = (C.mat[i][j] + (A.mat[i][k] * Q.mat[k][j])%mod)%mod;
	return C;
}
matrix powmul(matrix A, ll m)
{
	matrix ans = F;
	while (m > 0)
	{
		if (m & 1)
			ans = mul(ans, A);
		A = mul(A, A);
		m >>= 1;
	}
	return ans;
}
int main() {
	mod = 1000000007;
	ll a, b, n;
	cin >> a >> b;
	cin >> n;
		if (n == 1)
			cout << (a+mod)%mod << endl;
		else {
			U.mat[0][0] = 1; U.mat[0][1] = -1;
			U.mat[1][0] = 1; U.mat[1][1] = 0;

			F.mat[0][0] = b; F.mat[0][1] = 0;
			F.mat[1][0] = a; F.mat[1][1] = 0;
			matrix ans = powmul(U, n-1);
			cout << (ans.mat[1][0]+mod) %mod;
		}
	return 0;
}

问题七:

Reading comprehension

HDU - 4990

Read the program below carefully then answer the question.
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include<iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include<vector>

const int MAX=100000*2;
const int INF=1e9;

int main()
{
  int n,m,ans,i;
  while(scanf("%d%d",&n,&m)!=EOF)
  {
    ans=0;
    for(i=1;i<=n;i++)
    {
      if(i&1)ans=(ans*2+1)%m;
      else ans=ans*2%m;
    }
    printf("%d\n",ans);
  }
  return 0;
}

Input

Multi test cases,each line will contain two integers n and m. Process to end of file.
[Technical Specification]
1<=n, m <= 1000000000

Output

For each case,output an integer,represents the output of above program.

Sample Input

1 10
3 100

Sample Output

1
5

题意:根据题中代码求ans,但是不能直接用题目中的代码提交,当n很大的时候会超时,我们需要用快速幂优化。

分析:以2为一组,n=2时为ans(1),n=4时为ans(2),n=6时为ans(3),

则n为偶数时:n=n/2 ,ans(n)=4×ans(n-1)+2

n为奇数时:n先减1,n=n/2,求出ans(n)=4×ans(n-1)+2,先开始的时候n减了1,现在多算一步所以结果还要×2+1

矩阵:

代码:

 

#include<iostream>
#include<cstring>
#include<vector>
#include<cmath>
using namespace std;
typedef long long ll;
struct matrix
{
	ll mat[2][2];
	matrix() {
		memset(mat, 0, sizeof(mat));
	}
}U, F;
ll mod;
matrix mul(matrix Q, matrix A)
{
	matrix C;
	for (int i = 0; i < 2; i++)
		for (int j = 0; j < 2; j++)
			for (int k = 0; k < 2; k++)
				C.mat[i][j] = (C.mat[i][j] + (A.mat[i][k] * Q.mat[k][j]) % mod) % mod;
	return C;
}
matrix powmul(matrix A, ll m)
{
	matrix ans = F;
	while (m > 0)
	{
		if (m & 1)
			ans = mul(ans, A);
		A = mul(A, A);
		m >>= 1;
	}
	return ans;
}
int main() {
	ll n;
	while (cin >> n >> mod)
	{
		U.mat[0][0] = 4;
		U.mat[0][1] = 1;
		U.mat[1][0] = 0;
		U.mat[1][1] = 1;
		F.mat[0][0] = 2;
		F.mat[0][1] = 0;
		F.mat[1][0] = 2;
		F.mat[1][1] = 0;
		if (n == 1)
			cout << 1 % mod << endl;
		else if (n == 2)
			cout << 2 % mod << endl;
		else if (n == 3)
			cout << 5 % mod << endl;
		else 
		{
			matrix ans;
			if (n % 2 == 0)
			{
				n >>= 1;
			    ans = powmul(U, n-1);
				cout << ans.mat[0][0] %mod << endl;
			}
			else
			{
				n--;
				n >>= 1;
				ans = powmul(U, n-1);
				cout << (ans.mat[0][0]*2+1) % mod << endl;
			}
		}
	}
	//system("pause");
	return 0;
}

继续矩阵快速幂3:https://blog.csdn.net/qq_45364953/article/details/99771344

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值