C++矩阵加速—————Warcraft III 守望者的烦恼

版权声明:蒟蒻原创博客,大佬转载也需附上链接: https://blog.csdn.net/weixin_43810158/article/details/89232840

题目描述:

守望者-warden,长期在暗夜精灵的的首都艾萨琳内担任视察监狱的任务,监狱是成长条行的,守望者warden拥有一个技能名叫“闪烁”,这个技能可以把她传送到后面的监狱内查看,她比较懒,一般不查看完所有的监狱,只是从入口进入,然后再从出口出来就算完成任务了。

头脑并不发达的warden最近在思考一个问题,她的闪烁技能是可以升级的,k级的闪烁技能最多可以向前移动k个监狱,一共有n个监狱要视察,她从入口进去,一路上有n个监狱,而且不会往回走,当然她并不用每个监狱都视察,但是她最后一定要到第n个监狱里去,因为监狱的出口在那里,但是她并不一定要到第1个监狱。

守望者warden现在想知道,她在拥有k级闪烁技能时视察n个监狱一共有多少种方案?

输入:

第一行是闪烁技能的等级k(1<=k<=10)
第二行是监狱的个数n(1<=n<=2^31-1)

输出:

由于方案个数会很多,所以输出它 mod 7777777后的结果就行了

输入样例:

2
4

输出样例:

5

提示:

样例解释:

把监狱编号1 2 3 4,闪烁技能为2级,

一共有5种方案

→1→2→3→4

→2→3→4

→2→4

→1→3→4

→1→2→4

思路分析:

这一题的DP我们可以轻易看出,设f[i]为到i节点的方案数,而状态转移方程就是:

f[i]=\sum ^{i-1}_{j=i-k}\;f[j]

但是众所周知,2^{31}-1是一个较大的数,那么我们的矩阵加速就上场了。

设b为加速矩阵,假设k为4则:

b=\begin{bmatrix} 1 & 1 & 0 &0 \\ 1 & 0&1 &0 \\ 1 & 0 & 0& 1\\ 1 & 0 & 0 &0 \end{bmatrix}

我们再设一个矩阵ans[1][k]

其中ans[1][1]表示f[i]的值,而ans[1][2]为f[i-1],以此类推。

那我们的加速矩阵的作用就一目了然了。

第一列就是将f[i]的值求出,而之后的只不过是转移了。

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
#define ll long long
ll n1,mod=7777777,k;
struct node{
    ll n,m,c[15][15];
    node()
    {
        memset(c,0,sizeof(c));
    }
    node operator*(const node &a)
    {
        node r;
        r.n=n;
        r.m=a.m;
        for(int i=1;i<=r.n;i++)
            for(int j=1;j<=r.m;j++)
                for(int k=1;k<=m;k++)
                    r.c[i][j]=(r.c[i][j]+(c[i][k]*a.c[k][j])%mod)%mod;
        return r;
    }
}b,ans;
void qkpow(node a,ll x)
{
    while(x)
    {
        if(x&1)
            ans=ans*a;
        a=a*a;
        x/=2;
    }
}
int main()
{
    scanf("%lld%lld",&k,&n1);
    b.n=k;
    b.m=k;
    for(int i=1;i<=k;i++)
        b.c[i][1]=1;
    for(int i=1;i<=k;i++)
        b.c[i][i+1]=1;
    ans.n=1;
    ans.m=k;
    ans.c[1][1]=1;
    qkpow(b,n1);
    printf("%lld",ans.c[1][1]);
}

猜你喜欢

转载自blog.csdn.net/weixin_43810158/article/details/89232840
今日推荐