UOJ241(遞推+矩陣快速冪)

題目鏈接:UOJ241

先吐槽一下UOJ,額,註冊了沒做看題就要算參加的,可能是實在比較難參加的人比較少吧,傻傻地一場掉回解放前。

這是UR16的A題。

一句話題意:長度爲n的環,每個點染色,有m種顏色,要求相鄰相對不能同色,求方案數。(定義兩個點相對爲去掉這兩個點後環能被分成相同大小的兩段)

思路:
如果n是奇數,就轉化爲了一個比較簡單的遞推,可以像題解中那樣開兩維,也可以直接寫,如果第n-1個和第1個同色,則第n個有m - 1種塗色方案,這時有(m - 1) * f(n - 2)種方案,如果兩者不同色,則有(m - 2) * f(n - 1)種方案,化出來的矩陣應該是一樣的,但是考慮到偶數的情況,我發現開兩維會想的清楚許多。

如果n是偶數,那麼照題解中說的,多開一維,設 F[i][0..8]表示推到第 i 格的所有二元三進制狀態的合法方案數,然後遞推一波即可。其中設第一個顏色爲A,與其相對的格子顏色爲B。

然後一些邊界情況要考慮清楚。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>

using namespace std;

typedef long long ll;
typedef vector<ll> vec;
typedef vector<vec> mat;

const ll mod = 998244353;

mat mul(mat & A,mat & B){
    mat C(A.size(),vec(B[0].size()));
    for(int i = 0;i < (int) A.size();i++){
        for(int k = 0;k < (int) B.size();k++) if(A[i][k] != 0){
            for(int j = 0;j < (int)B[0].size();j++){
                C[i][j] = (C[i][j] + A[i][k] * B[k][j]) % mod;
            }
        }
    }
    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;
}

ll n,m;


int main(int argc, const char * argv[]) {
    cin >> n >> m;
    if(n & 1){
        if(m == 1){
            cout << 0 << endl;
            return 0;
        }
        mat A(2,vec(2));
        A[0][0] = (m - 2) % mod;
        A[0][1] = (m - 1) % mod;
        A[1][0] = 1;
        A[1][1] = 0;
        A = pow(A,n - 1);
        ll ans = A[0][1] * m % mod;
        cout << ans << endl;
    }else{
        if(m == 1){
            cout << 0 << endl;
            return 0;
        }
        if(n == 2){
            cout << m * (m - 1) % mod << endl;
            return 0;
        }else{
            if(m == 2){
                if(n % 4 == 0){
                    cout << 0 << endl;
                }else{
                    cout << 2 << endl;
                }
                return 0;
            }
            else{
                mat A(9,vec(9));
                for(int i = 0;i < 9;i++){
                    for(int j = 0;j < 9;j++){
                        A[i][j] = 0;
                    }
                }
                A[5][0] = 1;
                A[5][6] = 1;
                A[5][7] = 1;
                A[5][1] = 1;
                A[7][0] = 1;
                A[7][2] = 1;
                A[7][5] = 1;
                A[7][3] = 1;
                A[3][1] = (m - 2) % mod;
                A[3][0] = (m - 3) % mod;
                A[3][2] = (m - 2) % mod;
                A[3][6] = (m - 3) % mod;
                A[3][7] = (m - 2) % mod;
                A[1][3] = (m - 2) % mod;
                A[1][0] = (m - 3) % mod;
                A[1][6] = (m - 2) % mod;
                A[1][2] = (m - 3) % mod;
                A[1][5] = (m - 2) % mod;
                A[6][2] = (m - 2) % mod;
                A[6][0] = (m - 3) % mod;
                A[6][1] = (m - 2) % mod;
                A[6][3] = (m - 3) % mod;
                A[6][5] = (m - 2) % mod;
                A[2][6] = (m - 2) % mod;
                A[2][0] = (m - 3) % mod;
                A[2][3] = (m - 2) % mod;
                A[2][1] = (m - 3) % mod;
                A[2][7] = (m - 2) % mod;
                A[0][0] = ((m - 3) + (m == 3 ? 0 :(m - 4) * (m - 4))) % mod;
                A[0][1] = (m - 3) * (m - 3) % mod;
                A[0][2] = (m - 3) * (m - 3) % mod;
                A[0][3] = (m - 3) * (m - 3) % mod;
                A[0][5] = (m - 2) * (m - 3) % mod;
                A[0][6] = (m - 3) * (m - 3) % mod;
                A[0][7] = (m - 2) * (m - 3) % mod;
                A = pow(A,n / 2 - 1);
                ll ans = 0;
                ans += (A[0][5] + A[2][5] + A[3][5] + A[5][5]) % mod;
                ans = ans * m % mod * (m - 1) % mod;
                cout << ans << endl;
            }
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章