Description:
传球问题:
一共m个人,n次传球。
从小明手中传出,经过n次回到小明A手里的方案数。
Answer:
首先,我们知道,不管是A还是B,都不能自己传给自己,也就是说不能出现AA, BB这种情况。
设经过n次传球,回到小明手中的方案数为 a n a_n an。(第一种传球方式)
设经过n次传球,不回到小明手中的方案数为 b n b_n bn。(第二种传球方式)
很容易知道 b 1 = 1 , b 2 = m − 2 b_1=1,b_2=m-2 b1=1,b2=m−2
第一球传球方式:
第二种传球方式: 两种情况,一个是经过A传到B, 一个是经过不是A也不是B的传给B。
根据上述的式子我们可以得出:
b
n
=
b
n
−
2
∗
(
m
−
1
)
+
b
n
−
1
∗
(
m
−
2
)
b_n=b_{n-2}*(m-1)+b_{n-1}*(m-2)
bn=bn−2∗(m−1)+bn−1∗(m−2)
a
n
a_n
an可以根据第一个式子
a
n
=
b
n
−
1
∗
(
m
−
1
)
a_n=b_{n-1}*(m-1)
an=bn−1∗(m−1)计算得到。
这样我们求 a n a_n an可以转到求 b n − 1 b_{n-1} bn−1上面。所有的递推式基本都可以转换到矩阵快速幂上面来。之前介绍斐波那契的时候提到过,大家可以找一下我的博客,看一下。接下来,我们就可以得到下面的式子:
上面的
a
1
,
a
2
,
a
3
,
a
4
a_1, a_2, a_3, a_4
a1,a2,a3,a4没有其他的意义,只是代表
A
n
−
2
A^{n-2}
An−2的四个项。
所以, b n − 1 = a 1 + a 2 ∗ ( m − 2 ) b_{n-1}=a_1+a_2*(m-2) bn−1=a1+a2∗(m−2)。带入第一个式子, a n a_n an就求出来了。
下面举个例子,具体的题目:
小明现在正在带球组织进攻,目前他附近有n位队友可以进行传球配合。
小明作为主力射手,他希望和队友通过k次传球后,球还在自己脚下,并完成射门。
请计算这其中有多少种不同的传球方式。
输入:
正整数n和m,分别表示小明身边的队友数和传球次数。
输出:
不同的传球方式数(由于该数字可能很大,请输出总方式数对 10^9+7 的余数即可)
数据规模
对 20% 的数据:n = 1, 1 <= m <= 20
对 40% 的数据:1<= n <= 2, 1 <= m <= 10^5
对 70% 的数据:1 <= n <= 10, 1 <= m <= 10^18
对 100% 的数据: 1 <= n <= 10^9, 1 <= m <= 10^18
样例1输入
1 3
样例1输出
0
样例2输入
2 4
样例2输出
6
解题过程:
AC代码:
#include<bits/stdc++.h>
#include<iostream>
#define MAXNUM 1000000007
typedef unsigned long long ll;
using namespace std;
ll n, m;
//n个人, m次传球
//2*2的矩阵乘法
vector<vector<ll>> multiply(vector<vector<ll>> a, vector<vector<ll>> b){
vector<vector<ll>> res {{0,0}, {0,0}};
for(ll i=0; i<a.size(); i++){
for(ll j=0; j<b.size(); j++){
res[i][j] = (((a[i][0]%MAXNUM)*(b[0][j]%MAXNUM))%MAXNUM+((a[i][1]%MAXNUM)*(b[1][j]%MAXNUM))%MAXNUM)%MAXNUM;
}
}
return res;
}
//矩阵快速幂
vector<vector<ll>> fib_matrix(vector<vector<ll>> a, ll n){
//矩阵的0次幂是单位矩阵E
if(n == 0) return {{1,0},{0,1}};
else if( n&1 ){
return multiply(fib_matrix(a, n-1), a);
}else{
vector<vector<ll>> temp = fib_matrix(a, n/2);
return multiply(temp, temp);
}
}
int main(){
cin>>n>>m;
n = n+1;
//A[m](res)表示 从小明出发 传m次 传到小明的方案数
//B[m]表示从小明出发,传m次,传到B手中(不是小明)的方案数
//A[m]=B[m-1]*(n-1)
//B[m]=B[m-2]*(n-1)+B[m-1]*(n-2)
if(m==1) return 0;
//if(m==2) return n-1;
vector<vector<ll>> res = fib_matrix({{0,1},{n-1,n-2}}, m-2);
cout<<(((res[0][0]%MAXNUM+((res[0][1]%MAXNUM)*((n-2)%MAXNUM))%MAXNUM)%MAXNUM)*((n-1)%MAXNUM))%MAXNUM<<endl;
return 0;
}