zoukankan      html  css  js  c++  java
  • P1067Warcraft III 守望者的烦恼(十大矩阵问题之七求递推式)

    https://vijos.org/p/1067

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

    分析:快被自己蠢哭了,下午5点开始做这道题一直到现在,9点半。
    首先这道题要递推,得出递推式 f[n] = f[n-k] + f[n-k+1] + ...+f[n-1];怎么退出的呢?到n点分为起点从1开始,从2开始...从n-k(一个k就到n点了)开始,从1开始的方案数就是f[n-1],从2开始的就相当于从1到n-1,所以可以写成f[n-2],而从n-k点开始的呢,就直接是f[n-k];
    求这个递推式用矩阵来构造举例构造:f[n] = f[n-1] + f[n-2]+f[n-3]
    可以写成| 0 1 0 |    | f[n-3] |     | f[n-2] |
               | 0 0 1 | * | f[n-2] | =  | f[n-1] |
               | 1 1 1 |    | f[n-1] |     | f[n-3] + f[n-2] + f[n-1] |
    同理原式可以写成 k * K的矩阵,右上角的(k - 1)*(k - 1)主对角线都是一,第k行全为1;
    然后就可以写最原始的那个式子了,即:f[1]...f[k],
    最后根据n与k的关系分两种情况,k>=n,直接输出,n>k,利用矩阵快速幂求最后的变化矩阵,然后在用他左乘最原始的式子
    弱,弱爆了。。。
     1 #include <iostream>
     2 #include <cstring>
     3 #include <algorithm>
     4 #include <cstdio>
     5 using namespace std;
     6 
     7 int n,k;
     8 const int mod = 7777777;
     9 struct Mat
    10 {
    11     __int64 mat[20][20];
    12 };
    13 Mat operator * (Mat a, Mat b)
    14 {
    15     Mat c;
    16     memset(c.mat, 0, sizeof(c.mat));
    17     for(int t = 1; t <= k; t++)
    18     {
    19         for(int i = 1; i <= k; i++)
    20         {
    21             for(int j = 1; j <= k; j++)
    22                 c.mat[i][j] = ( c.mat[i][j] + a.mat[i][t] % mod * ( b.mat[t][j] % mod ) ) % mod;  //就是这里乘法忘了+c.mat[i][j]查了半个小时错,弱爆了
    23         }
    24     }
    25     return c;
    26 }
    27 Mat operator ^ (Mat a, int t)
    28 {
    29     Mat c;
    30     for(int i = 1; i <= k; i++)
    31         for(int j = 1; j <= k; j++)
    32             c.mat[i][j] = (i == j);
    33     while(t)
    34     {
    35         if(t & 1)
    36             c = a * c;
    37         a = a * a;
    38         t >>= 1;
    39     }
    40     return c;
    41 }
    42 int main()
    43 {
    44    scanf("%d%d", &k,&n);
    45    Mat ori,temp,res;
    46    memset(ori.mat, 0, sizeof(ori.mat));
    47    for(int i = 1; i <= k; i++)
    48    {
    49        for(int j = 1; j < i; j++) //这里是处理最原始的那个式子;假设求f[4] ,那么起点可以前3点作为起点,这个好像也能从自己作为起点,所以有个自加,就像f[1] = 1;
    50        {
    51            ori.mat[i][1] = (ori.mat[j][1] + ori.mat[i][1]) % mod;
    52        }
    53        ori.mat[i][1]++;
    54    }
    55    if(n <= k)
    56    {
    57        printf("%I64d
    ",ori.mat[n][1] % mod);
    58    }
    59    else
    60    {
    61        memset(temp.mat, 0, sizeof(temp.mat));
    62        for(int i = 1; i < k; i++)
    63        {
    64            temp.mat[i][i + 1] = 1;
    65        }
    66        for(int i = 1; i <= k; i++)
    67            temp.mat[k][i] = 1;
    68        res = temp ^ (n - k);
    69        ori = res * ori;
    70        printf("%I64d
    ", ori.mat[k][1] % mod);
    71    }
    72    return 0;
    73 }
    View Code
  • 相关阅读:
    android 监听ListView中的 item 和button
    android 获取当前系统及应用信息(二)
    MotionEvent中getX()和getRawX()的区别
    HITS 算法(Hypertext Induced Topic Selection)
    放之四海皆适用的设计原则(二)
    源自神话的写作要义之英雄之旅
    这就是搜索引擎:核心技术详解
    源自神话的写作要义之英雄
    使用Spinner和setDropDownViewResource
    友好界面menu
  • 原文地址:https://www.cnblogs.com/zhaopAC/p/5077061.html
Copyright © 2011-2022 走看看