Tsinsen D479 LiaPo

传送门
思路

对于前 30 % 的数据,就是普通的项链问题,直接 O ( 2 3 log n ) 解决。

对于 n 为偶数的情况,考虑一次填两个空,每次填 i i + n 2

f i , 0 / 1 / 2 , 0 / 1 / 2 表示从 1 填到 i 时,前半部分的结尾(不0)等于(前1后2)半部分的开头,后半部分的结尾(不0)等于(前2后1)半部分的开头时的方案数。有:

f 1 , 1 , 1 = 1

大力构造状态转移矩阵即可。事实上,当考虑第二颗珠子及以后的珠子时,不存在都为 1 或者都为 2 的状态,所以只需要考虑 7 × 7 = 49 种状态,是不是很少呢?

特别需要注意的是边界条件。当 i = 1 时,只有 f 1 , 1 = m ( m 1 ) ,其它都等于 0 。乘以 n 2 1 次转移矩阵就转移到了 i = n 2 的情况。最终答案不要加上与对面相等的情况(2)。

具体的转移矩阵见代码。代码假设 m 足够大,不会减出负数。

参考代码
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <cassert>
#include <cctype>
#include <climits>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <set>
#include <bitset>
#include <list>
#include <functional>
using LL = long long;
using ULL = unsigned long long;
using std::cin;
using std::cout;
using std::endl;
using INT_PUT = int;
INT_PUT readIn()
{
    INT_PUT a = 0;
    bool positive = true;
    char ch = getchar();
    while (!(std::isdigit(ch) || ch == '-')) ch = getchar();
    if (ch == '-')
    {
        positive = false;
        ch = getchar();
    }
    while (std::isdigit(ch))
    {
        (a *= 10) -= ch - '0';
        ch = getchar();
    }
    return positive ? -a : a;
}
void printOut(INT_PUT x)
{
    char buffer[20];
    int length = 0;
    if (x < 0) putchar('-');
    else x = -x;
    do buffer[length++] = -(x % 10) + '0'; while (x /= 10);
    do putchar(buffer[--length]); while (length);
}

const int mod = 998244353;
int n, m;

template<int size>
struct Matrix
{
    int c[size][size];
    Matrix() : c() {};
    explicit Matrix(bool) : Matrix()
    {
        for (int i = 0; i < size; i++)
            c[i][i] = 1;
    }
    int* operator[](int x) { return c[x]; }
    const int* operator[](int x) const { return c[x]; }
    Matrix operator*(const Matrix& b) const
    {
        Matrix ret;
        for (int i = 0; i < size; i++)
            for (int k = 0; k < size; k++) if (c[i][k])
                for (int j = 0; j < size; j++)
                    ret.c[i][j] = (ret.c[i][j] +
                    (LL)c[i][k] * b.c[k][j]) % mod;
        return ret;
    }
    Matrix operator^(int y) const
    {
        Matrix ret(true);
        Matrix x = *this;
        while (y)
        {
            if (y & 1) ret = ret * x;
            x = x * x;
            y >>= 1;
        }
        return ret;
    }
};

#define RunInstance(x) delete new x
struct cheat
{
    using Matrix = Matrix<2>;
    Matrix base;
    cheat()
    {
        if (n == 1)
        {
            printOut(m % mod);
            return;
        }
        base[0][0] = 0;
        base[0][1] = m - 1;
        base[1][0] = 1;
        base[1][1] = m - 2;
        Matrix ans = base ^ (n - 1);
        printOut((LL)m * (m - 1) % mod * ans[1][0] % mod);
    }
};
struct work
{
    using Matrix = Matrix<7>;

    work()
    {
        Matrix base;
        /*
        * 0: None
        * 1: Self
        * 2: Opposite
        * 0 - 0 0
        * 1 - 0 1
        * 2 - 0 2
        * 3 - 1 0
        * 4 - 1 1
        * 5 - 2 0
        * 6 - 2 2
        */

        base[0][0] = (std::max(LL(0), (LL)(m - 3) * (m - 3) - (m - 4))) % mod;
        base[0][1] = m - 3;
        base[0][2] = m - 3;
        base[0][3] = m - 3;
        base[0][4] = 1;
        base[0][5] = m - 3;
        base[0][6] = 1;

        base[1][0] = (std::max(LL(0), (LL)(m - 2) * (m - 3) - (m - 3))) % mod;
        base[1][1] = 0;
        base[1][2] = m - 3;
        base[1][3] = m - 2;
        base[1][4] = 0;
        base[1][5] = m - 2;
        base[1][6] = 1;

        base[2][0] = (std::max(LL(0), (LL)(m - 2) * (m - 3) - (m - 3))) % mod;
        base[2][1] = m - 3;
        base[2][2] = 0;
        base[2][3] = m - 2;
        base[2][4] = 1;
        base[2][5] = m - 2;
        base[2][6] = 0;

        base[3][0] = (std::max(LL(0), (LL)(m - 2) * (m - 3) - (m - 3))) % mod;
        base[3][1] = m - 2;
        base[3][2] = m - 2;
        base[3][3] = 0;
        base[3][4] = 0;
        base[3][5] = m - 3;
        base[3][6] = 1;

        base[4][0] = (std::max(LL(0), (LL)(m - 2) * (m - 2) - (m - 2))) % mod;
        base[4][1] = 0;
        base[4][2] = m - 2;
        base[4][3] = 0;
        base[4][4] = 0;
        base[4][5] = m - 2;
        base[4][6] = 1;

        base[5][0] = (std::max(LL(0), (LL)(m - 2) * (m - 3) - (m - 3))) % mod;
        base[5][1] = m - 2;
        base[5][2] = m - 2;
        base[5][3] = m - 3;
        base[5][4] = 1;
        base[5][5] = 0;
        base[5][6] = 0;

        base[6][0] = (std::max(LL(0), (LL)(m - 2) * (m - 2) - (m - 2))) % mod;
        base[6][1] = m - 2;
        base[6][2] = 0;
        base[6][3] = m - 2;
        base[6][4] = 1;
        base[6][5] = 0;
        base[6][6] = 0;

        base = base ^ ((n >> 1) - 1);
        LL ans = ((LL)base[4][0] + base[4][1] + base[4][3] + base[4][4]) % mod;
        printOut(ans * m % mod * (m - 1) % mod);
    }
};

void run()
{
    n = readIn();
    m = readIn();
    if (n & 1)
        RunInstance(cheat);
    else
        RunInstance(work);
}

int main()
{
#ifndef LOCAL
    freopen("LiaPo.in", "r", stdin);
    freopen("LiaPo.out", "w", stdout);
#endif
    run();
    return 0;
}
总结

增加状态,同时转移。

猜你喜欢

转载自blog.csdn.net/lycheng1215/article/details/80762242