18.03.26 vijos1067Warcraft III 守望者的烦恼

背景

守望者-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,否则可能会溢出

来源

杜杜我爱你个人原创

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <stdlib.h>
 5 #include <math.h>
 6 
 7 using namespace std;
 8 const int maxn=20,mod=7777777;
 9 long long int f[maxn];//存放到第几个监狱时的走法
10 
11 struct mat{
12     long long int a[maxn][maxn];
13 }res,ans;
14 
15 //matrix multiply j1*j2 n dimension(square)
16 mat cheng1(mat j1,mat j2,int n){
17     mat tmp;
18     for(int i=1;i<=n;i++)
19         for(int j=1;j<=n;j++)
20             tmp.a[i][j]=0;
21     for(int i=1;i<=n;i++)
22         for(int j=1;j<=n;j++)
23             for(int k=1;k<=n;k++)
24                 tmp.a[i][j]=(j1.a[i][k]*j2.a[k][j])%mod+tmp.a[i][j];
25     return tmp;
26 }
27 
28 
29 //quickpow k dimension n multi_n
30 mat qp(int k,int n){
31     for(int i=1;i<=k;i++)
32         for(int j=1;j<=k;j++){
33             if(i==j)ans.a[i][j]=1;
34             else ans.a[i][j]=0;
35         }
36     while(n){
37         if(n&1)
38             ans=cheng1(res,ans,k);
39         res=cheng1(res,res,k);
40         n>>=1;
41     }
42     return ans;
43 }
44 
45 int main()
46 {
47     int k,n;//k级 n个
48     scanf("%d%d",&k,&n);
49     f[0]=1;
50     for(int i=1;i<=k;i++){
51         f[i]=0;
52         for(int j=i-1;j>=0&&j>=i-k;j--){
53             f[i]+=f[j];
54         }
55     }
56     for(int i=1;i<=k-1;i++){
57         res.a[i][i+1]=1;
58         res.a[k][i]=1;
59     }
60     res.a[k][k]=1;
61     res=qp(k,n-k);
62     long long int m[maxn]={0};
63     for(int j=1;j<=k;j++){
64         m[k]+=res.a[k][j]*f[j];
65     }
66     printf("%lld
",m[k]%mod);
67     return 0;
68 }
View Code

大概是矩阵快速幂优化dp的经典题型,学习了

状态转移方程非常好想,所以一开始天真的我想用滚动数组把它全部循环一遍

然而数据太大了……当然是没法过的

所以要用矩阵乘法来缩短时间,算法了解一下->点这里

然后就是那个mod777...7……这句话我看了很久才明白是啥意思……

不过改完还是wa了几次,40分,原因是我只是在结果那边简单地%了一下mod(这有个毛用啊)

其实中间计算的时候数据就已经溢出了

所以又改了一下矩阵乘法计算过程中的数,因为反正都相当于是减了很多个mod所以对最后结果没有什么影响

注定失败的战争,也要拼尽全力去打赢它; 就算输,也要输得足够漂亮。
原文地址:https://www.cnblogs.com/yalphait/p/8650130.html