【Viojs1067】Warcraft 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

Copy

样例输出1

5

Copy

限制

各个测试点1s

提示

把监狱编号1 2 3 4,闪烁技能为2级,
一共有5种方案
→1→2→3→4
→2→3→4
→2→4
→1→3→4
→1→2→4

小提示:建议用int64,否则可能会溢出

 

解析:

       令f[i]表示到第i个监狱的方案数,则有:

       f[i]=\sum_{j=i-k}^{i-1}{f[j]}

       如果直接进行递推肯定是不行的,所以我们考虑构造矩阵。

       构造两个矩阵:

       \begin{pmatrix} 1& 1 & 0& 0& .&\\ .& 0& 1& 0& .&\\ .& 0& 0& 1& .&\\ .& .& .& 0& .&\\ 1& 0& 0& .& .& \end{pmatrix}

       \begin{pmatrix} f_{i}&f_{i-1} &...... &f_{i-k+1} &f_{i-k} \end{pmatrix}

       容易得出:

       \begin{pmatrix} f_{i}&f_{i-1} &...... &f_{i-k+1} &f_{i-k} \end{pmatrix}=\begin{pmatrix} f_{i-1}&f_{i-2} &...... &f_{i-k} &f_{i-k-1} \end{pmatrix}*\begin{pmatrix} 1& 1 & 0& 0& .&\\ .& 0& 1& 0& .&\\ .& 0& 0& 1& .&\\ .& .& .& 0& .&\\ 1& 0& 0& .& .& \end{pmatrix}

       于是矩阵快速幂即可。注意初始化f[0]=1

 

代码:

#include <bits/stdc++.h>
using namespace std;

const int mod=7777777;
const int Max=12;
int n,m,k;
int ans[Max],a[Max][Max];

inline int get_int()
{
	int x=0,f=1;
	char c;
	for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
	if(c=='-') f=-1,c=getchar();
	for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
	return x*f;
}

inline void mul(int ans[Max],int a[Max][Max])
{
	int c[Max];
	memset(c,0,sizeof(c));
	for(int j=1;j<=n;j++)
	  for(int k=1;k<=n;k++)
	    c[j]=(c[j]+1ll*ans[k]*a[k][j]%mod)%mod;
	memcpy(ans,c,sizeof(c));
}

inline void mulself(int a[Max][Max])
{
	int c[Max][Max];
	memset(c,0,sizeof(c));
	for(int i=1;i<=n;i++)
	  for(int j=1;j<=n;j++)
	    for(int k=1;k<=n;k++)
	      c[i][j]=(c[i][j]+1ll*a[i][k]*a[k][j]%mod)%mod;
	memcpy(a,c,sizeof(c));
}

inline void solve(int n)    //矩阵快速幂
{
	while(n)
	{
	  if(n&1) mul(ans,a);
	  n>>=1;
	  mulself(a);
	}
}

int main()
{
	n=get_int(),m=get_int();
	ans[1]=1;             //相当于初始化f[0]=0
	for(int i=1;i<=n;i++) a[i][1]=1;        //构造矩阵
	for(int i=1;i<=n;i++) a[i][i+1]=1;     //构造矩阵
	solve(m);
	cout<<ans[1]<<"\n";
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值