背景 Background | |||
守望者-warden,长期在暗夜精灵的的首都艾萨琳内担任视察监狱的任务,监狱是成长条行的,守望者warden拥有一个技能名叫“闪烁”,这个技能可以把她传送到后面的监狱内查看,她比较懒,一般不查看完所有的监狱,只是从入口进入,然后再从出口出来就算完成任务了。 | |||
描述 Description | |||
头脑并不发达的warden最近在思考一个问题,她的闪烁技能是可以升级的,k级的闪烁技能最多可以向前移动k个监狱,一共有n个监狱要视察,她从入口进去,一路上有n个监狱,而且不会往回走,当然她并不用每个监狱都视察,但是她最后一定要到第n个监狱里去,因为监狱的出口在那里,但是她并不一定要到第1个监狱。 守望者warden现在想知道,她在拥有k级闪烁技能时视察n个监狱一共有多少种方案? | |||
输入格式 Input Format | |||
第一行是闪烁技能的等级k(1<=k<=10) 第二行是监狱的个数n(1<=n<=2^31-1) | |||
输出格式 Output Format | |||
由于方案个数会很多,所以输出它 mod 7777777后的结果就行了 | |||
样例输入 Sample Input | |||
样例输出 Sample Output | |||
时间限制 Time Limitation | |||
各个测试点1s | |||
注释 Hint | |||
把监狱编号1 2 3 4,闪烁技能为2级, 一共有5种方案 →1→2→3→4 →2→3→4 →2→4 →1→3→4 →1→2→4 小提示:建议用int64,否则可能会溢出 | |||
来源 Source | |||
杜杜我爱你个人原创 | |||
这道题主要要搞清楚题意。
也就是说,第一步只能到达1~k的房间,因为第一步就要闪烁。
所有就是求从1、2、3、4…k到n的方案总数。
f[i] = f[0]+f[1]+...+f[i-1] (i <= k)
f[i] = f[i-k]+f[i-k+1]+...+f[i-1] (i > k)
这个可以用矩阵乘法,不过明显1到k需要手动算,因为方程不一样。
注意:同余定理也适用于矩阵。。。(不知道为什么,但是我没有一直取余就会爆,还好试了一组大数据)
另外,7777777*7777777+7777777会爆long int。所以要用64位长整。
还有,为了安全起见,矩阵要赋初值0(不是指空矩阵,空矩阵是主对角线为1),不然在乘法时肯定会出错。
#include <cstdio>
#include <string>
#include <cstring>
typedef long long ll;
struct Rect
{
ll r[13][13];
Rect(){memset(r,0,sizeof r);}
void operator=(const Rect&r2){memcpy(r,r2.r,sizeof r);}
};
Rect mult;
Rect ans;
long k,n;
void multiply(Rect &r1,const Rect &r2)
{
Rect tmp;
for (long i=1;i<k+1;i++)
{
for (long j=1;j<k+1;j++)
{
for (long l=1;l<k+1;l++)
{
tmp.r[i][j] = (tmp.r[i][j]+r1.r[i][l]*r2.r[l][j])%7777777;
}
}
}
r1 = tmp;
}
void quickpower(long a)
{
while (a)
{
if (a&1){multiply(ans,mult);}
multiply(mult,mult);
a >>= 1;
}
}
long f[15];
int main()
{
freopen("warden.in","r",stdin);
freopen("warden.out","w",stdout);
scanf("%ld%ld",&k,&n);
f[0] = 1;
for (long i=1;i<k+1;i++)
{
for (long j=i-1;j>-1&&i-j<=k;j--)
{
f[i] += f[j];
}
}
if (n <= k)
{
printf("%ld",f[n]);
return 0;
}
for (long i=1;i<k;i++)
mult.r[i][i+1] = 1;
for (long i=1;i<k+1;i++)
mult.r[k][i] = 1;
for (long i=1;i<k+1;i++)
ans.r[i][i] = 1;
quickpower(n-k);
ll out = 0;
for (long i=1;i<k+1;i++)
{
out = (out + f[i]*ans.r[k][i])%7777777;
}
printf("%ld",out);
return 0;
}