[矩陣快速冪]hdu2604 Queuing

hdu2604 Queuing

題意:
f代表女性,m代表男性,排成縱隊,長度爲L的隊列方案數有2^L種,如果某個隊列存在"fmf"或"fff"子隊列,那麼這個隊列是O-queue,否則是E-queue
求E-queue的數目%MOD後的值
思路:
用f(n)表示n長度的E序列數目,此題倒推
如果最後一位是m,前面無限制,求f(n-1)即可
如果最後一位是f,前面有限制,往前推一位,mf ff,這兩個都有限制,再往前推一位,fmf mmf fff mff,其中fmf和fff不符合條件我們不考慮,
如果是mmf,前面無限制,求f(n-3)即可,
如果是mff,前面有限制,往前推一位,fmff mmff,fmff不符合條件我們不考慮,mmff前面無限制,求f(n-4)即可
至此,對於當前的f(n)來說,所有情況都已考慮到,我們可以寫出式子:
f(n) = f(n-1) + f(n-3) + f(n-4)
顯然不能直接遞歸,時間會跪,所以我們轉化成矩陣


看大神說也可以用trie圖表示,有字符串fmf和fff構建trie圖


假定根節點爲字符串的最後一個字符,由根結點到根節點的迴路有m、fmm、ffmm,注意這是從一個字符串的後面向前走這些字符到達另一個字符串,恰好和上面的擴展遞推相一致

這個圖還是比較迷的……

代碼:

/**************************************************************
    Problem: HDU_2604
    User: soundwave
    Language: C++
    Result: Accepted
    Time: 280ms
    Memory: 1576KB
****************************************************************/
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <stdio.h>
#include <vector>
/*
感覺這個推公式還是比較麻煩的,因爲還有許多重複項
所以還是推出關係式,用矩陣乘法求比較好
f(n) = f(n-1) + f(n-3) + f(n-4);
A^
*/
using namespace std;
typedef vector<int>Vint;
typedef vector<Vint>VVint;
typedef __int64 LL;
int MOD;
//矩陣乘法
VVint calc(VVint &A, VVint &B){
    VVint C(A.size(), Vint(A.size()));
    for(int i=0; i<A.size(); i++)
    for(int j=0; j<B[0].size(); j++)
    for(int k=0; k<B.size(); k++)
        C[i][j] = (C[i][j] + (A[i][k]*B[k][j])%MOD) % MOD;
    return C;
}
//二分快速冪
VVint my_pow(VVint &A, int c){
    VVint B(A.size(), Vint(A.size()));
    for(int i=0; i<A.size(); i++)
        B[i][i] = 1;
    if(c==1) return A;
    while(c>0){
        if(c&1) B = calc(B,A);
        A = calc(A,A);
        c>>=1;
    }
    return B;
}
int main(){
    int k;
    while(~scanf("%d%d", &k, &MOD)){
        VVint A(4, Vint(4));
        int B[5] = {0,2,4,6,9};
        if(k<5){
            printf("%d\n", B[k]%MOD);
            continue;
        }
        A[0][0] = A[0][2] = A[0][3] = 1;
        A[1][0] = A[2][1] = A[3][2] = 1;
        A = my_pow(A,k-4);
        int re = 0;
        for(int i=0; i<4; i++)
            re = (re + (A[0][i]*B[4-i])%MOD) % MOD;
        printf("%d\n", re);
    }
    return 0;
}
/*
0 1 2 3 4
0 2 4 6 9
----------
0 0
Null
1 2
f m
2 4
ff mm fm mf
3 6
[fff] ffm [fmf] fmm mff mfm mmf mmm
4 9
[ffff] [fffm] [ffmf] ffmm
[fmff] [fmfm] fmmf fmmm
[mfff] mffm [mfmf] mfmm
mmff mmfm mmmf mmmm
5 2^5-17=15
[fffff] [ffffm] [fffmf] [fffmm]
[ffmff] [ffmfm] [ffmmf] ffmmm
[fmfff] [fmffm] [fmfmf] [fmfmm]
fmmff fmmfm fmmmf fmmmm
[mffff] [mfffm] mffmf mffmm
[mfmff] [mfmfm] mfmmf mfmmm
[mmfff] mmffm [mmfmf] mmfmm
mmmff mmmfm mmmmf mmmmm
*/


發佈了76 篇原創文章 · 獲贊 106 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章