UOJ241(递推+矩阵快速幂)

原创 2016年08月29日 11:11:48

题目链接: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;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

NYOJ 301 递推求值(矩阵快速幂)

递推求值 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 给你一个递推公式: f(x)=a*f(x-2)+b*f(x-1)+c 并给你f(1),f(2)的...
  • LYHVOYAGE
  • LYHVOYAGE
  • 2014年04月04日 12:25
  • 3146

矩阵快速幂专题(一)

最近闲来无事,准备集中精力刷一波数论与图论。矩阵快速幂是数论里面的重要组成部分,值得我好好学习一下。因为题目比较多,分析也比较多,所以将此专题分成几个部分。做完这一专题,可能会暂时转向图论部分,然后等...
  • shengtao96
  • shengtao96
  • 2016年03月25日 22:45
  • 1060

根据递推公式构造系数矩阵用于快速幂

简单的例子FibonacciFibonacci数列考虑FibonacciFibonacci数列, F(n)=F(n−1)+F(n−2)F(n)=F(n-1)+F(n-2) 将右边两项看做是一个列向...
  • u012061345
  • u012061345
  • 2016年08月16日 21:51
  • 901

矩阵快速幂总结

矩阵快速幂 基础知识:(会基础的直接看应用部分) (1) 矩阵乘法 简单的说矩阵就是二维数组,数存在里面,矩阵乘法的规则:A*B=C 其中c[i][j]为A的第i行与B的第j列对应乘积的和,即: ...
  • wust_zzwh
  • wust_zzwh
  • 2016年11月25日 15:40
  • 8123

算法学习 - 快速幂和矩阵快速幂(复杂度Olog(n))C++实现

快速幂 快速幂顾名思义,就是快速算某个数的多少次幂。其时间复杂度为 O(log₂N), 与朴素的O(N)相比效率有了极大的提高。 快速幂实现原理 快速幂的原理比较好懂,就是说假如我们...
  • chenfs1992
  • chenfs1992
  • 2014年12月24日 22:51
  • 7746

POJ3070矩阵快速幂求Fib

欲哭无泪。。。。。比赛的时候都敲不出来。。 Fibonacci Time Limit: 1000MS   Memory Limit: 65536K Tota...
  • u012350533
  • u012350533
  • 2013年10月08日 23:50
  • 931

快速幂或者矩阵快速幂

快速幂或者矩阵快速幂在算指数时是很高效的,他的基本原理是二进制,下面的A可以是一个数也可以是一个矩阵(本文特指方阵),若是数就是快速幂算法,若是矩阵就是矩阵快速幂算法,用c++只需把矩阵设成一个类就可...
  • u011401504
  • u011401504
  • 2013年08月04日 22:17
  • 10102

java实现矩阵快速幂算法

java实现矩阵快速幂算法
  • y937498174
  • y937498174
  • 2015年04月24日 09:53
  • 1124

一类常见的矩阵快速幂题型 总结

Googlecode jam 2008 Round 1A(c.Numbers) 【题意】计算的小数点前三位数,不足三位补0,正整数n的最大值为20亿。 【前提】:满足 的值在【0,1】范围 首...
  • u013050857
  • u013050857
  • 2015年09月21日 23:59
  • 1030

快速幂,矩阵快速幂原理介绍

快速幂:复杂度为logn,比普通的n快了很多了.原理 :以求a的b次方来介绍: 首先把b转换成二进制数 该二进制数第i位的权为 2^i - 1 . 比如 : 11的二进制是1011 11 = 2³×...
  • Anxdada
  • Anxdada
  • 2017年06月21日 13:49
  • 284
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:UOJ241(递推+矩阵快速幂)
举报原因:
原因补充:

(最多只允许输入30个字)