2020.7.20【算协集训】矩阵快速幂

算法分析与排序

  • A - Fibonacci (POJ - 3070)
    • 分析
    • 代码
  • B - Tr A (HDU - 1575)
    • 分析
    • 代码
  • C - A Simple Math Problem (HDU - 1757)
    • 分析
    • 代码
  • D - Recursive sequence (HDU - 5950)
    • 分析
    • 代码
  • E - ProjectEuler 48 (51Nod - 2182)
    • 分析
    • 代码
  • F - 求递推序列的第N项 (51Nod - 1126)
    • 分析
    • 代码
  • G - 人见人爱A^B (HDU - 2035)
    • 分析
    • 代码

网页链接:传送门
密码:hpucam

A - Fibonacci (POJ - 3070)

菲波那契数列是指这样的数列: 数列的第一个是0和第二个数是1,接下来每个数都等于前面2个数之和。 给出一个正整数a,要求菲波那契数列中第a个数的后四位是多少。
Input
多组数据 -1结束 范围1~10^9
Output
第x项的后4位

Sample Input Sample Output
0
9
999999999
1000000000
-1
0
34
626
6875

分析

这题要用到矩阵快速幂
已知 数列的第一个是0和第二个数是1,接下来每个数都等于前面2个数之和,我们可以设成: f ( 0 ) = 0 , f ( 1 ) = 1 , f ( n ) = f ( n − 1 ) + f ( n − 2 ) f(0)=0,f(1)=1,f(n)=f(n-1)+f(n-2) f(0)=0,f(1)=1,f(n)=f(n1)+f(n2)
因此我们可以构建式子: [ f ( n + 1 ) f ( n ) ] = [ 1 1 1 0 ] [ f ( n ) f ( n − 1 ) ] = [ 1 1 1 0 ] n [ f ( 1 ) f ( 0 ) ] = [ 1 1 1 0 ] n [ 1 0 ] \left[ \begin{matrix} f(n+1) \\ f(n) \end{matrix} \right]= \left[ \begin{matrix} 1 & 1 \\ 1 & 0 \end{matrix} \right] \left[ \begin{matrix} f(n) \\ f(n-1) \end{matrix} \right]=\left[ \begin{matrix} 1 & 1 \\ 1 & 0 \end{matrix} \right]^{n} \left[ \begin{matrix} f(1) \\ f(0) \end{matrix} \right]=\left[ \begin{matrix} 1 & 1 \\ 1 & 0 \end{matrix} \right]^{n} \left[ \begin{matrix} 1 \\ 0 \end{matrix} \right] [f(n+1)f(n)]=[1110][f(n)f(n1)]=[1110]n[f(1)f(0)]=[1110]n[10]

因此,我们只需要计算 [ 1 1 1 0 ] n \left[ \begin{matrix} 1 & 1 \\ 1 & 0 \end{matrix} \right]^{n} [1110]n 的值,最后因为我们要的是 f ( n ) f(n) f(n) ,因此只需要输出 ( b . m [ 2 ] [ 1 ] + m o d ) % m o d (b.m[2][1]+mod)\%mod (b.m[2][1]+mod)%mod 或者 b . m [ 2 ] [ 1 ] % m o d b.m[2][1]\%mod b.m[2][1]%mod 就可以了。

代码

#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int mod=10000;	//要求后四位数,只需要对10000求余
struct node
{
	ll m[3][3];
};
node mul(node a,node b)	//矩阵相乘
{
	node temp;	//临时矩阵,存放a×b的结果
	memset(temp.m,0,sizeof(temp.m));
	for(int i=1;i<3;i++)
	{
		for(int j=1;j<3;j++)
		{
			for(int k=1;k<3;k++)
			{
				temp.m[i][j]+=(a.m[i][k]*b.m[k][j])%mod;
			}
		}
	}
	return temp;
}
node qpower(node a,ll b)	//快速幂
{
	node temp;
	memset(temp.m,0,sizeof(temp.m));
	for(int i=1;i<3;i++)	//单位矩阵
		temp.m[i][i]=1;
	while(b)
	{
		if(b&1)	temp=mul(temp,a);
		a=mul(a,a);
		b>>=1;
	}
	return temp;	
}
int main()
{
	ll n;
	while(~scanf("%lld",&n))
	{
		if(n==-1)	break;
		node a,b;	//a是最初方阵,b是结果方阵
		a.m[1][1]=1,a.m[1][2]=1;
		a.m[2][1]=1,a.m[2][2]=0;
		b=qpower(a,n);
		printf("%lld\n",(b.m[2][1]+mod)%mod);
	}
	return 0;
}

B - Tr A (HDU - 1575)

A为一个方阵,则Tr A表示A的迹(就是主对角线上各项的和),现要求Tr(A^k)%9973。
Input
数据的第一行是一个T,表示有T组数据。
每组数据的第一行有n(2 <= n <= 10)和k(2 <= k < 10^9)两个数据。接下来有n行,每行有n个数据,每个数据的范围是[0,9],表示方阵A的内容。
Output
对应每组数据,输出Tr(A^k)%9973。

Sample Input Sample Output
2
2 2
1 0
0 1
3 99999999
1 2 3
4 5 6
7 8 9
0
34
626
6875

分析

方阵是行数与列数相等的矩阵。对于方阵 A A A,只需要利用矩阵快速幂,计算 A k % 9973 A^k\%9973 Ak%9973 的值就可以了。

注意计算过程中也要 % 9973 \%9973 %9973,以免出现溢出现象。

代码

#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int mod=9973;
ll k,tr;
int T,n;
struct node
{
	ll m[15][15];
}res,ans;	//ans是结果方阵,res是初始方阵
node mul(node a,node b)	//矩阵相乘
{
	node temp;	//临时矩阵,存放a×b的结果
	memset(temp.m,0,sizeof(temp.m));
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<n;j++)
		{
			for(int k=0;k<n;k++)
			{
				temp.m[i][j]+=(a.m[i][k]*b.m[k][j])%mod;
			}
		}
	}
	return temp;
}
void qpower(int a,int b)	//快速幂
{
	for(int i=0;i<b;i++)	//单位矩阵
	{
		for(int j=0;j<b;j++)
		{
			if(i==j)	ans.m[i][j]=1;
			else	ans.m[i][j]=0;
		}
	}
	while(a)
	{
		if(a&1)	ans=mul(ans,res);
		res=mul(res,res);
		a>>=1;
	}	
}
int main()
{
	cin>>T;
	while(T--)
	{
		cin>>n>>k;
		for(int i=0;i<n;i++)	//储存初始方阵的值
		{
			for(int j=0;j<n;j++)
			{
				cin>>res.m[i][j];
			}
		}
		qpower(k,n);	//计算结果方阵
		tr=0;
		for(int i=0;i<n;i++)	//计算主对角线上各项的和
			tr=(tr+ans.m[i][i])%mod;
		cout<<tr%mod<<endl;
	}
	return 0;
}

C - A Simple Math Problem (HDU - 1757)

Lele now is thinking about a simple function f(x).
If x < 10 f(x) = x.
If x >= 10 f(x) = a0 ∗ * f(x-1) + a1 ∗ * f(x-2) + a2 ∗ * f(x-3) + …… + a9 ∗ * f(x-10);
And ai(0<=i<=9) can only be 0 or 1 .
Now, I will give a0 ~ a9 and two positive integers k and m ,and could you help Lele to caculate f(k)%m.
Input
The problem contains mutiple test cases.Please process to the end of file.
In each case, there will be two lines.
In the first line , there are two positive integers k and m. ( k<2*109 , m < 105 )
In the second line , there are ten integers represent a0 ~ a9.
Output
For each case, output f(k) % m in one line.

Sample Input Sample Output
10 9999
1 1 1 1 1 1 1 1 1 1
20 500
1 0 1 0 1 0 1 0 1 0
45
104

分析

题意:对于 f ( x ) = { x , x < 10 a 0 ∗ f ( x − 1 ) + a 1 ∗ f ( x − 2 ) + a 2 ∗ f ( x − 3 ) + … … + a 9 ∗ f ( x − 10 ) , x ≥ 10 f(x)=\begin{cases}x, x<10\\a_0 * f(x-1) + a_1 * f(x-2) + a_2 * f(x-3) + …… + a_9 * f(x-10),x≥10\end{cases} f(x)={xx<10a0f(x1)+a1f(x2)+a2f(x3)++a9f(x10)x10,且 a i ∈ 0 或 1 a_i∈0或1 ai01 ,给你 k k k m m m ,让你计算 f ( k ) % m f(k)\%m f(k)%m 的值。

为了提高效率,我们进行分类讨论。当输入的 k k k 的值 < 10 <10 10时,直接输出 k % m k\%m k%m 的值。而对于 k ≥ 10 k≥10 k10 的情况,我们进行以下详细讨论:
f ( x ) = a 0 ∗ f ( x − 1 ) + a 1 ∗ f ( x − 2 ) + a 2 ∗ f ( x − 3 ) + … … + a 9 ∗ f ( x − 10 ) f(x)=a_0 * f(x-1) + a_1 * f(x-2) + a_2 * f(x-3) + …… + a_9 * f(x-10) f(x)=a0f(x1)+a1f(x2)+a2f(x3)++a9f(x10),由此我们可以构建式子:
[ f ( n ) f ( n − 1 ) f ( n − 2 ) f ( n − 3 ) f ( n − 4 ) f ( n − 5 ) f ( n − 6 ) f ( n − 7 ) f ( n − 8 ) f ( n − 9 ) ] = [ a 0 a 1 a 2 a 3 a 4 a 5 a 6 a 7 a 8 a 9 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 ] n − 9 [ f ( 9 ) f ( 8 ) f ( 7 ) f ( 6 ) f ( 5 ) f ( 4 ) f ( 3 ) f ( 2 ) f ( 1 ) f ( 0 ) ] = [ a 0 a 1 a 2 a 3 a 4 a 5 a 6 a 7 a 8 a 9 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 ] n − 9 [ 9 8 7 6 5 4 3 2 1 0 ] \left[ \begin{matrix} f(n) \\ f(n-1) \\ f(n-2) \\ f(n-3) \\ f(n-4) \\ f(n-5) \\ f(n-6) \\ f(n-7) \\ f(n-8) \\ f(n-9) \end{matrix} \right]= \left[ \begin{matrix} a_0 & a_1 & a_2 & a_3 & a_4 & a_5 & a_6 & a_7 & a_8 & a_9 \\ 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \end{matrix} \right]^{n-9} \left[ \begin{matrix} f(9) \\ f(8) \\ f(7) \\ f(6) \\ f(5) \\ f(4) \\ f(3) \\ f(2) \\ f(1) \\ f(0) \end{matrix} \right]=\left[ \begin{matrix} a_0 & a_1 & a_2 & a_3 & a_4 & a_5 & a_6 & a_7 & a_8 & a_9 \\ 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \end{matrix} \right]^{n-9} \left[ \begin{matrix} 9 \\ 8 \\ 7 \\ 6 \\ 5 \\ 4 \\ 3 \\ 2 \\ 1 \\ 0 \end{matrix} \right] f(n)f(n1)f(n2)f(n3)f(n4)f(n5)f(n6)f(n7)f(n8)f(n9)=a0100000000a1010000000a2001000000a3000100000a4000010000a5000001000a6000000100a7000000010a8000000001a9000000000n9f(9)f(8)f(7)f(6)f(5)f(4)f(3)f(2)f(1)f(0)=a0100000000a1010000000a2001000000a3000100000a4000010000a5000001000a6000000100a7000000010a8000000001a9000000000n99876543210
因此,我们只需要先利用矩阵快速幂,解出 [ a 0 a 1 a 2 a 3 a 4 a 5 a 6 a 7 a 8 a 9 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 ] n − 9 \left[ \begin{matrix} a_0 & a_1 & a_2 & a_3 & a_4 & a_5 & a_6 & a_7 & a_8 & a_9 \\ 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \end{matrix} \right]^{n-9} a0100000000a1010000000a2001000000a3000100000a4000010000a5000001000a6000000100a7000000010a8000000001a9000000000n9的值,再让结果矩阵的第一行与 [ 9 8 7 6 5 4 3 2 1 0 ] \left[ \begin{matrix} 9 \\ 8 \\ 7 \\ 6 \\ 5 \\ 4 \\ 3 \\ 2 \\ 1 \\ 0 \end{matrix} \right] 9876543210逐个相乘求余后相加,就能够得到我们想要得到的 f ( n ) f(n) f(n) 的值。

代码

#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N=10;
ll k,m,sum;
struct node
{
	ll a[N][N];
}res,ans;	//ans是结果矩阵,res是初始方阵
node mul(node a,node b)	//矩阵相乘
{
	node temp;	//临时矩阵,存放a*b的结果
	memset(temp.a,0,sizeof(temp.a));
	for(int i=0;i<N;i++)
	{
		for(int j=0;j<N;j++)
		{
			for(int k=0;k<N;k++)
			{
				temp.a[i][j]+=(a.a[i][k]*b.a[k][j])%m;
			}
		}
	}
	return temp;
}
void qpower(int a,int b)	//快速幂
{
	for(int i=0;i<N;i++)	//单位矩阵
	{
		for(int j=0;j<N;j++)
		{
			if(i==j)	ans.a[i][j]=1;
			else	ans.a[i][j]=0;
		}
	}
	while(a)
	{
		if(a&1)	ans=mul(ans,res);
		res=mul(res,res);
		a>>=1;
	}	
}
int main()
{
	while(~scanf("%lld%lld",&k,&m))
	{
		memset(res.a,0,sizeof(res.a));	//清空初始矩阵
		for(int i=0;i<N;i++)	//给初始矩阵赋值
		{
			scanf("%d",&res.a[0][i]);
		}
		for(int i=1;i<N;i++)
		{
			res.a[i][i-1]=1;
		}
		if(k<10)	printf("%lld\n",k%m);	//如果k<10,那么f(k)的值已经确定是k了,因此可以直接求余计算并输出。
		else
		{
			qpower(k-9,N);	//计算结果矩阵
			sum=0;
			for(int i=0;i<N;i++)
			{
				sum+=ans.a[0][i]*(9-i)%m;
			}
			printf("%lld\n",sum%m);
		}
	}
	return 0;
}

D - Recursive sequence (HDU - 5950)

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 Sample Output Hint
2
3 1 2
4 1 10
85
369
In the first case, the third number is 85 = 2 ∗ * 1十2十34.
In the second case, the third number is 93 = 2 ∗ * 1十1 ∗ * 10十34 and the fourth number is 369 = 2 ∗ * 10 十 93 十 44.

分析

题意:有递推式 f ( n ) = f ( n − 1 ) + 2 f ( n − 2 ) + n 4 , f ( 1 ) = a , f ( 2 ) = b f(n)=f(n-1)+2f(n-2)+n^4,f(1)=a,f(2)=b f(n)=f(n1)+2f(n2)+n4,f(1)=a,f(2)=b ,输入 n , a , b n,a,b n,a,b 的值,让你计算 f ( n ) f(n) f(n) 的值。

这题也是和前面的题一样,需要构建式子。 难点在于 n 4 n^4 n4 的构建。这里我们根据题目给的式子,我们还可以把它写成 f ( n + 1 ) = f ( n ) + 2 f ( n − 1 ) + ( n + 1 ) 4 , f ( 1 ) = a , f ( 2 ) = b f(n+1)=f(n)+2f(n-1)+(n+1)^4,f(1)=a,f(2)=b f(n+1)=f(n)+2f(n1)+(n+1)4,f(1)=a,f(2)=b 。而 ( n + 1 ) 4 = n 4 + 4 n 3 + 6 n 2 + 4 n + 1 , ( n + 1 ) 3 = n 3 + 3 n 2 + 3 n + 1 , ( n + 1 ) 2 = n 2 + 2 n + 1 (n+1)^4=n^4+4n^3+6n^2+4n+1,(n+1)^3=n^3+3n^2+3n+1,(n+1)^2=n^2+2n+1 (n+1)4=n4+4n3+6n2+4n+1,(n+1)3=n3+3n2+3n+1,(n+1)2=n2+2n+1,我们就可以利用 n 4 , n 3 , n 2 , n 1 , n 0 n^4,n^3,n^2,n^1,n^0 n4,n3,n2,n1,n0 来构建式子:
[ f ( n ) f ( n − 1 ) ( n + 1 ) 4 ( n + 1 ) 3 ( n + 1 ) 2 ( n + 1 ) 1 ( n + 1 ) 0 ] = [ 1 2 1 0 0 0 0 1 0 0 0 0 0 0 0 0 1 4 6 4 1 0 0 0 1 3 3 1 0 0 0 0 1 2 1 0 0 0 0 0 1 1 0 0 0 0 0 0 1 ] [ f ( n − 1 ) f ( n − 2 ) n 4 n 3 n 2 n 1 n 0 ] = [ 1 2 1 0 0 0 0 1 0 0 0 0 0 0 0 0 1 4 6 4 1 0 0 0 1 3 3 1 0 0 0 0 1 2 1 0 0 0 0 0 1 1 0 0 0 0 0 0 1 ] n − 2 [ f ( 2 ) f ( 1 ) 3 4 3 3 3 2 3 1 3 0 ] \left[ \begin{matrix} f(n) \\ f(n-1) \\ (n+1)^4 \\ (n+1)^3 \\ (n+1)^2 \\ (n+1)^1 \\ (n+1)^0 \end{matrix} \right]= \left[ \begin{matrix} 1 & 2 & 1 & 0 & 0 & 0 & 0 \\ 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 1 & 4 & 6 & 4 & 1 \\ 0 & 0 & 0 & 1 & 3 & 3 & 1 \\ 0 & 0 & 0 & 0 & 1 & 2 & 1 \\ 0 & 0 & 0 & 0 & 0 & 1 & 1 \\ 0 & 0 & 0 & 0 & 0 & 0 & 1 \end{matrix} \right] \left[ \begin{matrix} f(n-1) \\ f(n-2) \\ n^4 \\ n^3 \\ n^2 \\ n^1 \\ n^0 \\ \end{matrix} \right]=\left[ \begin{matrix} 1 & 2 & 1 & 0 & 0 & 0 & 0 \\ 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 1 & 4 & 6 & 4 & 1 \\ 0 & 0 & 0 & 1 & 3 & 3 & 1 \\ 0 & 0 & 0 & 0 & 1 & 2 & 1 \\ 0 & 0 & 0 & 0 & 0 & 1 & 1 \\ 0 & 0 & 0 & 0 & 0 & 0 & 1 \end{matrix} \right]^{n-2} \left[ \begin{matrix} f(2) \\ f(1) \\ 3^4 \\ 3^3 \\ 3^2 \\ 3^1 \\ 3^0 \\ \end{matrix} \right] f(n)f(n1)(n+1)4(n+1)3(n+1)2(n+1)1(n+1)0=1100000200000010100000041000006310000432100011111f(n1)f(n2)n4n3n2n1n0=1100000200000010100000041000006310000432100011111n2f(2)f(1)3433323130
因此,我们只需要先利用矩阵快速幂,解出 [ 1 2 1 0 0 0 0 1 0 0 0 0 0 0 0 0 1 4 6 4 1 0 0 0 1 3 3 1 0 0 0 0 1 2 1 0 0 0 0 0 1 1 0 0 0 0 0 0 1 ] n − 2 \left[ \begin{matrix} 1 & 2 & 1 & 0 & 0 & 0 & 0 \\ 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 1 & 4 & 6 & 4 & 1 \\ 0 & 0 & 0 & 1 & 3 & 3 & 1 \\ 0 & 0 & 0 & 0 & 1 & 2 & 1 \\ 0 & 0 & 0 & 0 & 0 & 1 & 1 \\ 0 & 0 & 0 & 0 & 0 & 0 & 1 \end{matrix} \right]^{n-2} 1100000200000010100000041000006310000432100011111n2 的值之后,让结果矩阵的第一行分别与 [ b a 81 27 9 3 1 ] \left[ \begin{matrix} b \\ a \\ 81 \\ 27 \\ 9 \\ 3 \\ 1 \\ \end{matrix} \right] ba8127931 相乘取余,就是我们想要的 f ( n ) f(n) f(n) 的值了。

代码

#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N=7;
const ll m=2147493647;	//记得是ll
ll n,A,B,sum;
struct node
{
	ll a[N][N];
}res,ans;	//ans是结果矩阵,res是初始方阵
node mul(node a,node b)	//矩阵相乘
{
	node temp;	//临时矩阵,存放a*b的结果
	memset(temp.a,0,sizeof(temp.a));
	for(int i=0;i<N;i++)
	{
		for(int j=0;j<N;j++)
		{
			for(int k=0;k<N;k++)
			{
				temp.a[i][j]=(temp.a[i][j]+a.a[i][k]*b.a[k][j])%m;
			}
		}
	}
	return temp;
}
void qpower(int a,int b)	//快速幂
{
	for(int i=0;i<b;i++)	//单位矩阵
	{
		for(int j=0;j<b;j++)
		{
			if(i==j)	ans.a[i][j]=1;
			else	ans.a[i][j]=0;
		}
	}
	while(a)
	{
		if(a&1)	ans=mul(ans,res);
		res=mul(res,res);
		a>>=1;
	}	
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%lld%lld%lld",&n,&A,&B);
		res.a[0][0]=1,res.a[0][1]=2,res.a[0][2]=1,res.a[0][3]=0,res.a[0][4]=0,res.a[0][5]=0,res.a[0][6]=0;
		res.a[1][0]=1,res.a[1][1]=0,res.a[1][2]=0,res.a[1][3]=0,res.a[1][4]=0,res.a[1][5]=0,res.a[1][6]=0;
		res.a[2][0]=0,res.a[2][1]=0,res.a[2][2]=1,res.a[2][3]=4,res.a[2][4]=6,res.a[2][5]=4,res.a[2][6]=1;
		res.a[3][0]=0,res.a[3][1]=0,res.a[3][2]=0,res.a[3][3]=1,res.a[3][4]=3,res.a[3][5]=3,res.a[3][6]=1;
		res.a[4][0]=0,res.a[4][1]=0,res.a[4][2]=0,res.a[4][3]=0,res.a[4][4]=1,res.a[4][5]=2,res.a[4][6]=1;
		res.a[5][0]=0,res.a[5][1]=0,res.a[5][2]=0,res.a[5][3]=0,res.a[5][4]=0,res.a[5][5]=1,res.a[5][6]=1;
		res.a[6][0]=0,res.a[6][1]=0,res.a[6][2]=0,res.a[6][3]=0,res.a[6][4]=0,res.a[6][5]=0,res.a[6][6]=1;
		if(n==1)	printf("%lld\n",A%m);
		else if(n==2)	printf("%lld\n",B%m);
		else
		{
			qpower(n-2,N);	//计算结果矩阵
			sum=0;
			sum=(sum+ans.a[0][0]*B)%m;
			sum=(sum+ans.a[0][1]*A)%m;
			sum=(sum+ans.a[0][2]*81)%m;
			sum=(sum+ans.a[0][3]*27)%m;
			sum=(sum+ans.a[0][4]*9)%m;
			sum=(sum+ans.a[0][5]*3)%m;
			sum=(sum+ans.a[0][6]*1)%m;
			printf("%lld\n",sum%m);
		}
	}
	return 0;
}

E - ProjectEuler 48 (51Nod - 2182)

考虑求和
11+22+33+⋯+1010=10405071317
输入n,求
11+22+33+⋯+nn
对 1010 取模的结果。
Input
输入第一行组数T, 接下来T行,每行一个整数n。 (1 <= T <= 1000) (1 <= N <= 1000)
Output
对于每组数据,输出一个数,表示求和对10000000000取模的结果。

Sample Input Sample Output
4
1
10
100
1000
1
405071317
9027641920
9110846700

分析

这题因为一开始没有讲快速乘,所以卡了一段时间,然后在网上找了一篇还不错的博客,这里是链接,有机会再自己总结⑧。

因为每种快速乘的写法的时间复杂度都不一样,我这里就列了两种不同的写法。按这些写法都可以AC。

代码

  1. 第一种写法
    #include
    #include
    #include
    #include
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const ll maxn=1010;
    const ll MOD=1e10;
    int T,N;
    ll sum[maxn],cnt;
    ll ksc(ll x,ll y,ll mod)
    {
    	ll z=(ld)x/mod*y;
    	ll res=(ull)x*y-(ull)z*mod;
    	return (res+mod)%mod;
    }
    ll qpow(ll x,ll y,ll mod)
    {
    	ll res=1;
    	while(y)
    	{
    		if(y&1)	res=ksc(res,x,mod);
    		x=ksc(x,x,mod);
    		y>>=1;
    	}
    	return res%mod;
    }
    int main()
    {
    	scanf("%d",&T);
    	while(T--)
    	{
    		scanf("%d",&N);
    		cnt=0;
    		for(int i=1;i<=N;i++)
    		{
    			cnt=(cnt+qpow(i,i,MOD)+MOD)%MOD;
    		}
    		printf("%lld\n",cnt);
    	}
    	return 0;
    }
    
  2. 第二种写法
    #include
    #include
    #include
    #include
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const ll maxn=1010;
    const ll MOD=1e10;
    int T,N;
    ll sum[maxn],cnt;
    ll ksc(ll x,ll y,ll mod)
    {
    	ll res=0;
    	while(y)
    	{
    		if(y&1)	res=(res+x)%mod;
    		x=(x<<1)%mod;
    		y>>=1;
    	}
    	return res%mod;
    }
    ll qpow(ll x,ll y,ll mod)
    {
    	ll res=1;
    	while(y)
    	{
    		if(y&1)	res=ksc(res,x,mod);
    		x=ksc(x,x,mod);
    		y>>=1;
    	}
    	return res%mod;
    }
    void init()
    {
    	for(int i=1;i<maxn;i++)
    	{
    		sum[i]=(sum[i-1]+qpow(i,i,MOD)+MOD)%MOD;
    	}
    }
    int main()
    {
    	scanf("%d",&T);
    	init();
    	while(T--)
    	{
    		scanf("%d",&N);
    		printf("%lld\n",sum[N]);
    	}
    	return 0;
    }
    

F - 求递推序列的第N项 (51Nod - 1126)

有一个序列是这样定义的:f(1) = 1, f(2) = 1, f(n) = (A ∗ * f(n - 1) + B ∗ * f(n - 2)) mod 7.
给出A,B和N,求f(n)的值。
Input
输入3个数:A,B,N。数字之间用空格分割。(-10000 <= A, B <= 10000, 1 <= N <= 10^9)
Output
输出f(n)的值。

Sample Input Sample Output
3 -1 5 6

分析

此题的题意题目写的挺清楚了,给定 A , B , N A,B,N A,B,N 的值,让你求出 f ( N ) f(N) f(N) 的值。
而对于 f ( n ) f(n) f(n) ,有: f ( n ) = { 1 , n = 1 或 2 ( A ∗ f ( n − 1 ) + B ∗ f ( n − 2 ) ) m o d 7 , n ≠ 1 或 2 f(n)=\begin{cases}1,n=1或2\\(A*f(n - 1)+B*f(n - 2)) mod 7,n≠1或2\end{cases} f(n)={1n=12(Af(n1)+Bf(n2))mod7n=12
因此我们可以构建式子:
[ f ( n ) f ( n − 1 ) ] = [ A B 1 0 ] [ f ( n − 1 ) f ( n − 2 ) ] = [ A B 1 0 ] n − 2 [ f ( 2 ) f ( 1 ) ] = [ A B 1 0 ] n − 2 [ 1 1 ] \left[ \begin{matrix} f(n) \\ f(n-1) \end{matrix} \right]= \left[ \begin{matrix} A & B \\ 1 & 0 \end{matrix} \right] \left[ \begin{matrix} f(n-1) \\ f(n-2) \end{matrix} \right]=\left[ \begin{matrix} A & B \\ 1 & 0 \end{matrix} \right]^{n-2} \left[ \begin{matrix} f(2) \\ f(1) \end{matrix} \right]=\left[ \begin{matrix} A & B \\ 1 & 0 \end{matrix} \right]^{n-2} \left[ \begin{matrix} 1 \\ 1 \end{matrix} \right] [f(n)f(n1)]=[A1B0][f(n1)f(n2)]=[A1B0]n2[f(2)f(1)]=[A1B0]n2[11]
所以,我们可以利用矩阵快速幂,求出 [ A B 1 0 ] n − 2 \left[ \begin{matrix} A & B \\ 1 & 0 \end{matrix} \right]^{n-2} [A1B0]n2的值, f ( n ) f(n) f(n) 的值就是结果矩阵的第一行元素之和并对 7 7 7 求余。

代码

#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MOD=7;
const int maxn=10;
ll A,B,N;
ll k,m,sum;
struct node
{
	ll m[3][3];
}res,ans;	//ans是结果矩阵,res是初始方阵
node mul(node a,node b)	//矩阵相乘
{
	node temp;	//临时矩阵,存放a×b的结果
	memset(temp.m,0,sizeof(temp.m));
	for(int i=1;i<3;i++)
	{
		for(int j=1;j<3;j++)
		{
			for(int k=1;k<3;k++)
			{
				temp.m[i][j]+=(a.m[i][k]*b.m[k][j])%MOD;
			}
		}
	}
	return temp;
}
void qpower(int a,int b)	//快速幂
{
	for(int i=1;i<b;i++)	//单位矩阵
	{
		for(int j=1;j<b;j++)
		{
			if(i==j)	ans.m[i][j]=1;
			else	ans.m[i][j]=0;
		}
	}
	while(a)
	{
		if(a&1)	ans=mul(ans,res);
		res=mul(res,res);
		a>>=1;
	}	
}
int main()
{
	scanf("%lld%lld%lld",&A,&B,&N);
	res.m[1][1]=A,res.m[1][2]=B;
	res.m[2][1]=1,res.m[2][2]=0;
	if(N==1 || N==2)	printf("1");
	else
	{
		qpower(N-2,3);
		printf("%lld",(ans.m[1][1]+ans.m[1][2]+MOD)%MOD);
	}
	return 0;
}

G - 人见人爱A^B (HDU - 2035)

求A^B的最后三位数表示的整数。
说明:A^B的含义是“A的B次方”
Input
输入数据包含多个测试实例,每个实例占一行,由两个正整数A和B组成(1<=A,B<=10000),如果A=0, B=0,则表示输入数据的结束,不做处理。
Output
对于每个测试实例,请输出A^B的最后三位表示的整数,每个输出占一行。

Sample Input Sample Output
2 3
12 6
6789 10000
0 0
8
984
1

分析

这题我之前的题解写过了,这里放一下链接。
直接套快速幂的模板就可。

代码

#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
ll A,B;
ll qpow(ll x,ll y,ll mod)	//快速幂板子
{
	ll res=1;
	while(y)
	{
		if(y&1)	res=(res*x)%mod;
		x=(x*x)%mod;
		y>>=1;
	}
	return res;
}
int main()
{
	while(~scanf("%lld%lld",&A,&B))
	{
		if(A==0 && B==0)	break;
		printf("%lld\n",qpow(A,B,1000)%1000);
	}
	return 0;
}

你可能感兴趣的:(题解)