VOJ1067 【矩阵经典7 构造矩阵】

任意门:https://vijos.org/records/5be95b65d3d8a1366270262b

背景

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

题意概括:

给出可闪现的距离 K 房间个数 N,问到达终点的方案数;

解题思路:

很明显的DP,DP的转移方程也显而易见 F(N) = F(N-1)+F(N-2)+ ... + F(N-K);

找出递推式,很显然可以用矩阵来优化,并且系数为 1,So easy!

以为到这就解决问题了,太粗心啦,注意数据范围,注意数据精度!!!要用 long long

Ac code:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#define LL long long
using namespace std;
const int MAXN = 11;
const LL Mod  = 7777777;
int N, K;

struct mat
{
    LL m[MAXN][MAXN];
}base, tmp, ans;

mat muti(mat a, mat b)
{
    mat res;
    memset(res.m, 0, sizeof(res.m));

    for(int i = 1; i <= K; i++)
    for(int j = 1; j <= K; j++){
        if(a.m[i][j]){
            for(int k = 1; k <= K; k++){
                res.m[i][k] = (res.m[i][k] + a.m[i][j]*b.m[j][k])%Mod;
//                res.m[i][k] = res.m[i][k]%Mod;
            }
        }
    }
    return res;
}

mat qpow(mat a, int n)
{
    mat res;
    memset(res.m, 0, sizeof(res));
    for(int i = 1; i <= K; i++) res.m[i][i] = 1LL;
    while(n){
        if(n&1) res = muti(res, a);
        n>>=1;
        a = muti(a, a);
    }
    return res;
}

int main()
{
    scanf("%d%d", &K, &N);
    memset(base.m, 0, sizeof(base.m));
    base.m[0][1] = 1LL;
    for(int i = 1; i <= K; i++){
        for(int j = 0; j < i; j++)
            base.m[i][1] += base.m[j][1]%Mod;
    }

    if(N <= K) printf("%lld
", base.m[N][1]);
    else{
        memset(tmp.m, 0, sizeof(tmp.m));
        for(int i = 1; i < K; i++){
            tmp.m[i][i+1] = 1LL;
        }
        for(int i = 1; i <= K; i++) tmp.m[K][i] = 1LL;

        tmp = qpow(tmp, N-K);
        mat ans = muti(tmp, base);

        printf("%lld
", ans.m[K][1]%Mod);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/ymzjj/p/9948370.html