1. 程式人生 > >hdu6030 Happy Necklace(矩陣快速冪+遞推式)

hdu6030 Happy Necklace(矩陣快速冪+遞推式)

思路來源

https://www.cnblogs.com/bolderic/p/7216739.html

題意

給你一個長為n的珠子串,要求你給這條串塗色,

要求任意素數長度的串中,紅色數不少於藍色數,只有紅藍兩色。

問長為n的串的塗色方案數。

題解

這個遞推式還是挺好想的,就是好久不用矩陣快速冪一下愣住了。

dp寫久了小範圍的用不了矩陣快速冪的還是把自己寫傻了QAQ

注意到任意素數長度都成立,則任意2個必有1個紅珠,任意3個必有2個紅珠。

則剩下顯然能推出5個必有3個,7個必有4個…以此類推,所以只看2個和3個即可。

1 紅 藍 ans=2

2 紅紅 藍紅 紅藍 ans=3

3 紅紅紅 藍紅紅 紅藍紅 紅紅藍 ans=4

4 紅紅紅紅 藍紅紅紅 紅藍紅紅 紅紅藍紅 紅紅紅藍 藍紅紅藍 ans=6

這麼多就足以說明問題了,

注意到an至少等於an-1,

若第n個珠子為紅,an-1的方案後補一個紅珠即可,

若第n個珠子為藍,由藍藍、藍紅藍兩種情況不能出現,

說明該種情況一定由XXXXX紅紅轉移而來,XXXXX部分任意,對應an-3的方案數。

即有an=an1+an-3,矩陣快速冪一波就可以了。

\begin{bmatrix} a_{n+3}\\ a_{n+2}\\ a_{n+1}\\ \end{bmatrix}=\begin{bmatrix} 1 & 0 & 1\\ 1 & 0 & 0\\ 0 & 1 & 0 \end{bmatrix}*\begin{bmatrix} a_{n+2}\\ a_{n+1}\\ a_{n}\\ \end{bmatrix},一波矩陣快速冪即可

心得

還是得多做題,不然反應不過來,順便屯個板子gg

程式碼

#include <iostream>
#include <algorithm> 
#include <cstring>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>
#include <functional>
const int INF=0x3f3f3f3f;
const int maxn=1e5+10; 
const int mod=1e9+7;
const int MOD=998244353;
const double eps=1e-7;
typedef long long ll;
#define vi vector<int> 
#define si set<int>
#define pii pair<int,int> 
#define pi acos(-1.0)
#define pb push_back
#define mp make_pair
#define lowbit(x) (x&(-x))
#define sci(x) scanf("%d",&(x))
#define scll(x) scanf("%lld",&(x))
#define sclf(x) scanf("%lf",&(x))
#define pri(x) printf("%d",(x))
#define rep(i,j,k) for(int i=j;i<=k;++i)
#define per(i,j,k) for(int i=j;i>=k;--i)
#define mem(a,b) memset(a,b,sizeof(a)) 
using namespace std;
const int inf = 0x3f3f3f3f;
typedef vector<long long> vec;
typedef vector<vec> mat;

mat mul(mat &A, mat &B){
    mat C(A.size(), vec(B[0].size()));
    for(int i = 0; i < A.size(); i++){
        for(int k = 0; k < B.size(); k++){
            for(int j = 0; j < B[0].size(); j++){
                C[i][j] = (C[i][j] + A[i][k] * B[k][j]) % mod;
            }
        }.j,j
    }
    return C;
}

mat pow(mat A, ll n){
    mat B(A.size(), vec(A.size()));
    for(int i = 0; i < A.size(); i++){
        B[i][i] = 1;
    }
    while(n > 0){
        if(n & 1) B = mul(B, A);
        A = mul(A, A);
        n >>= 1; 
    }
    return B;
}

int main()
{
    int t;
    scanf("%d", &t);
    while(t--){
        long long n;
        scanf("%lld", &n);
        mat A(3, vec(3));
        A[0][0] = 1; A[0][1] = 0; A[0][2] = 1;
        A[1][0] = 1; A[1][1] = 0; A[1][2] = 0;
        A[2][0] = 0; A[2][1] = 1; A[2][2] = 0;
        A = pow(A, n - 2);
        ll ans = (A[2][0] * 6 + A[2][1] * 4 + A[2][2] * 3) % mod;
        printf("%lld\n", ans);
    }
    return 0; 
}