2018ICPC焦作- Poor God Water 求递推式+矩阵快速幂

Posted the-way-of-cas

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2018ICPC焦作- Poor God Water 求递推式+矩阵快速幂相关的知识,希望对你有一定的参考价值。

题目链接:https://nanti.jisuanke.com/t/31721

题意:一个孩子吃饭,有meat, fish 和 chocolate 三种食物可以选。要求连续三顿饭食物不能完全相同,鱼和肉的前一顿和后一顿不能都是巧克力,巧克力的左右两边不能同时出现鱼和肉。

思路:分九种情况,求出递推式,写出标准矩阵,用矩阵快速幂。

代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#define maxn 10000000009
#define MOD    1000000007
#define ll long long
using namespace std;

ll jz[10][10] = { {0, 0,0,0,0,0,0,0,0,0},
                {0, 0,0,0,1,0,0,1,0,0},
                {0, 1,0,0,0,0,0,1,0,0},
                {0, 1,0,0,1,0,0,1,0,0},
                {0, 0,1,0,0,1,0,0,0,0},
                {0, 0,1,0,0,0,0,0,1,0},
                {0, 0,0,0,0,1,0,0,1,0},
                {0, 0,0,1,0,0,1,0,0,1},
                {0, 0,0,1,0,0,0,0,0,1},
                {0, 0,0,1,0,0,1,0,0,0} };
struct juzhen {
    ll a[10][10];
}arr[35];
ll n, t;

void mulmod(ll a, ll b, ll &c) {
    ll a1, a2, b1, b2;
    a1 = a >> 1;
    a2 = a - a1;
    b1 = b >> 1;
    b2 = b - b1;
    
    c += (a1*b1) % MOD ;
    c %= MOD;
    c += (a1*b2) % MOD;
    c %= MOD;
    c += (a2*b1) % MOD;
    c %= MOD;
    c += (a2*b2) % MOD;
    c %= MOD;
}

void jzxjz(juzhen x, juzhen y, juzhen &jieguo) {
    for (int i = 1; i <= 9; i++) {
        for (int j = 1; j <= 9; j++) {
            jieguo.a[i][j] = 0;
            for (int k = 1; k <= 9; k++) {
                mulmod(x.a[i][k], y.a[k][j], jieguo.a[i][j]);
            }
        }
    }
}

int findmax(int l,int r,ll n) { //不要递归,会超时
    int mid;
    while (r-l>1)
    {
        mid = (l + r) >> 1;
        mid++;
        if (n >= 1ll << mid) {
            l = mid;
        }
        else r = mid - 1;
    }
    return l;
}

void muljz(ll n, juzhen &jzn) {
    for (int i = 1; i <= 9; i++) {
        for (int j = 1; j <= 9; j++) {
            jzn.a[i][j] = !(j ^ i);
        }
    }

    int k;
    while (n>0)
    {
        k = findmax(0, 34, n);
        jzxjz(jzn, arr[k], jzn);
        n -= 1ll << k;
    }
}
void setarr() {  //arr[k] 代表初始矩阵的2^k次幂
    for (int i = 1; i <= 9; i++) {
        for (int j = 1; j <= 9; j++) {
            arr[0].a[i][j] = jz[i][j];
        }
    }
    for (int i = 1; i <= 34; i++) {
        jzxjz(arr[i - 1], arr[i - 1], arr[i]);
    }
}
int main()
{
    setarr();
    juzhen jzn1;
    ll ans;

    scanf("%lld", &t);
    while (t--) {
        scanf("%lld", &n);
        if (n == 2) {
            printf("%d
", 9);
            continue;
        }
        if (n == 1) {
            printf("%d
", 3);
            continue;
        }

        muljz(n - 2, jzn1);
        ans = 0;
        for (int i = 1; i <= 9; i++) {
            for (int j = 1; j <= 9; j++) {
                ans += jzn1.a[i][j];
                ans %= MOD;
            }
        }
        printf("%lld
", ans);
    }
    return 0;
}

 

以上是关于2018ICPC焦作- Poor God Water 求递推式+矩阵快速幂的主要内容,如果未能解决你的问题,请参考以下文章

ACM-ICPC 2018 焦作赛区网络预赛 L:Poor God Water(矩阵快速幂)

2018ICPC焦作- Poor God Water 求递推式+矩阵快速幂

L. Poor God Water(ACM-ICPC 2018 焦作赛区网络预赛)

ACM-ICPC 2018 焦作赛区网络预赛 Poor God Water 矩阵快速幂

ACM-ICPC 2018 焦作赛区网络预赛 L:Poor God Water(杜教BM)

2018焦作网络赛 - Poor God Water 一道水题的教训