背景
守望者-warden,长期在暗夜精灵的的首都艾萨琳内担任视察监狱的任务,监狱是成长条行的,守望者warden拥有一个技能名叫“闪烁”,这个技能可以把她传送到后面的监狱内查看,她比较懒,一般不查看完所有的监狱,只是从入口进入,然后再从出口出来就算完成任务了。
描述
头脑并不发达的warden最近在思考一个问题,她的闪烁技能是可以升级的,k级的闪烁技能最多可以向前移动k个监狱,一共有n个监狱要视察,她从入口进去,一路上有n个监狱,而且不会往回走,当然她并不用每个监狱都视察,但是她最后一定要到第n个监狱里去,因为监狱的出口在那里,但是她并不一定要到第1个监狱。
守望者warden现在想知道,她在拥有k级闪烁技能时视察n个监狱一共有多少种方案?
格式
输入格式
第一行是闪烁技能的等级k(1<=k<=10)
第二行是监狱的个数n(1<=n<=2^31-1)
输出格式
由于方案个数会很多,所以输出它 mod 7777777后的结果就行了
样例1
样例输入1
2
4
样例输出1
5
限制
各个测试点1s
提示
把监狱编号1 2 3 4,闪烁技能为2级,
一共有5种方案
→1→2→3→4
→2→3→4
→2→4
→1→3→4
→1→2→4
小提示:建议用int64,否则可能会溢出
这题是群里一朋友发的,看到这题我觉得很有必要练练。
思路:
递推加矩阵快速幂。我们都知道斐波那契数列F[n]=F[n-2]+F[n-1]这题,我们可以根据斐波那契的思路进行递推,我们知道他每次只能闪现1~k即[1,k]都可以选择,所以我们容易得出,当n∈[1,k]时,方法数为2^(n-1)。之后>k的每一个方法数,都是通过前k项之和得出。所以容易写出方程F[n]=F[n-1]+F[n-2]+······+F[n-k],但是这里n的取值比较大,因此不能用O(n)的方式,需要用加速幂求解。根据矩阵的基本性质,我们只需要根据n之前的k项推出此时的n即可
如假设k=4 我们就需要预处理4个值,然后从第5个开始计算
![]()
根据图形我们可知,两个矩阵都随着k的变化而变化,第一个矩阵总是1*k第二个总是k*k,因此可以编写代码了,需要注意的是仔细别写错
代码可能写的也不是很好,欢迎提建议
代码:
import java.util.Scanner;
public class _WarcraftIII守望者的烦恼 {
private static int k;
private static long n;
private static final long MOD = 7777777;
public static void main(String[] args) {
Scanner sn = new Scanner(System.in);
k = sn.nextInt();
n = sn.nextLong();
long[][] ans = new long[2][k+1]; //放置最终答案
long[][] matrix = new long[k+1][k+1]; //放置加速的矩阵
long[][] final_matrix = new long[k+1][k+1]; //放置单位初始矩阵
ans[1][k] = 1;
for(int i = 1;i<=k;i++){
ans[1][k-i] = ans[1][k-i+1]*2;
final_matrix[i][i] = 1;
matrix[i][1] = 1;
if(i<k)matrix[i][i+1] = 1;
}
if(n>k){
n=n-k;
while(n>0){//加速幂
if((n&1)==1)
final_matrix = matrix_multiply(final_matrix,matrix);
matrix = matrix_multiply(matrix,matrix);
n>>=1;
}
ans = matrix_multiply(ans,final_matrix);
System.out.println(ans[1][1]);
}else{
System.out.println(ans[1][(int) (k-n+1)]);//如果n<=k那么直接输出预处理的答案
}
sn.close();
}
private static long[][] matrix_multiply(long[][] final_matrix,long[][] matrix) {
int len1 = final_matrix.length;
long[][] temp = new long[len1][k+1];
for(int i = 1;i<len1;i++){
for(int j = 1;j<=k;j++){
for(int z = 1;z<=k;z++)
temp[i][j]=(temp[i][j]+final_matrix[i][z]*matrix[z][j])%MOD;
}
}
return temp;
}
}