POJ 3734 Blocks

题目链接

递推 + 矩阵快速幂优化

/*
题意,有n个块,用 0, 1, 2, 3来染色
求0, 1块数为偶数的方案数

a[i] 表示前i个0,1块都为偶数的方案数
b[i] 表示前i个0,1块一奇一偶的方案数
c[i] 表示前i个0,1块都为奇数的方案数

a[i] = 2*a[i-1] + b[i-1]
b[i] = 2*a[i-1] + b[i-1]*2 + 2*c[i-1]
c[i] = b[i-1] + c[i-1]*2
然后可以写成矩阵快速幂

  a[i]       2, 1, 0       a[i-1]
( b[i] ) = ( 2, 2, 2 ) * ( b[i-1] )
  c[i]       0, 1, 2       c[i-1]

*/
#include
#include
#include
#include
#include
using namespace std;

inline int gi() {
    int x = 0, f = 1;
    char c = getchar();
    while (c != '-' && (c < '0' || c > '9'))
        c = getchar();
    if (c == '-') {
        f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') x = x*10+c-48, c = getchar();
    return f*x;
}
const int mod = 10007;
struct node {
    int s[5][5];
    node operator *(node z) const{
        node d;
        for (int i = 1; i <= 3; i++) {
            for (int j = 1; j <= 3; j++) {
                d.s[i][j] = 0;
                for (int k = 1; k <= 3; k++) {
                    d.s[i][j] += (s[i][k] * z.s[k][j])%mod;
                    d.s[i][j] %= mod;
                }
            }
        }
        return d;
    }
}a, ans;

void ksm(int x) {
    memset(ans.s, 0, sizeof(ans.s));
    ans.s[1][1] = ans.s[2][2] = ans.s[3][3] = 1;
    while (x) {
        if (x&1) {
            ans = ans*a;
        }
        a = a*a;
        x >>= 1;
    }
    return ;
}
int ss[4] = {0, 2, 2, 0};//初始值

void work() {
    int n = gi();
    a.s[1][3] = a.s[3][1] = 0;
    a.s[2][1] = a.s[2][3] = a.s[1][1] = a.s[2][2] = a.s[3][3] = 2;
    a.s[1][2] = a.s[3][2] = 1;
    ksm(n-1);
    int res = 0;
    for (int i = 1; i <= 3; i++)
        res += ss[i] * ans.s[1][i], res %= mod;
    printf("%d\n", res);
    return ;
}

int main() {
    int t = gi();
    while (t--) work();
    return 0;
}

你可能感兴趣的:(POJ)