P1357 花园 (矩阵快速幂+ DP)

Posted lwqq3

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1357 花园 (矩阵快速幂+ DP)相关的知识,希望对你有一定的参考价值。

题意:一个只含字母C和P的环形串

   求长度为n且每m个连续字符不含有超过k个C的方案数 

   m <= 5  n <= 1e15

题解:用一个m位二进制表示状态 转移很好想

   但是这个题是用矩阵快速幂加速dp的 因为每一位的转移都是一样的

   用一个矩阵表示状态i能否转移到状态j 然后跑一遍

   初试模板题

 

技术图片
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;

ll n, m, k, len;
struct node 
    ll c[64][64];
re, x;

bool check(int x) 
    int cnt = 0;
    while(x) 
        if(x & 1) cnt++;
        x >>= 1;
    
    if(cnt > k) return false;
    return true;


node mul(node a, node b) 
    node res;
    memset(res.c, 0, sizeof(res.c));

    for(int i = 0; i < len; i++)
    for(int j = 0; j < len; j++)
    for(int k = 0; k < len; k++)
        res.c[i][j] = (res.c[i][j] + a.c[i][k] * b.c[k][j] % mod) % mod;
    return res;


node pow_mod(node x, ll y) 
    node res;
    for(int i = 0; i < len; i++) res.c[i][i] = 1;

    while(y) 
        if(y & 1) res = mul(res, x);
        x = mul(x, x);
        y >>= 1;
    
    return res;


int main() 
    scanf("%lld%lld%lld", &n, &m, &k);
    len = (1 << m);
    for(int i = 0; i < len; i++)
    for(int j = 0; j < len; j++)
        x.c[i][j] = 0;

    for(int i = 0; i < len; i++) 
        if(!check(i)) continue;
        int tmp = i;
        int ctmp = 1 << (m - 1);
        if((tmp & ctmp) == ctmp) tmp -= ctmp;
        tmp <<= 1;
        if(check(tmp)) x.c[i][tmp] = 1;
        tmp |= 1;
        if(check(tmp)) x.c[i][tmp] = 1;
    
    re = pow_mod(x, n);

    ll ans = 0;
    for(int i = 0; i < len; i++) 
        if(check(i)) 
            ans += re.c[i][i];
            ans %= mod;
        
    
    printf("%lld\n", ans);
    return 0;
View Code

 

以上是关于P1357 花园 (矩阵快速幂+ DP)的主要内容,如果未能解决你的问题,请参考以下文章

luogu P1357 花园

[luogu1357] 花园 [dp+矩阵快速幂]

2/11 矩阵快速幂+dp+二分

BZOJ 4000: [TJOI2015]棋盘( 状压dp + 矩阵快速幂 )

CodeForces621E 快速矩阵幂优化dp

hdu5564--Clarke and digits(数位dp+矩阵快速幂)