【题解】P4456 [CQOI2018] 交错序列(矩阵乘法)

P4456 CQOI2018 交错序列 - 洛谷 (luogu.com.cn)

0.分析

所谓的交错序列,如果只看数量,有:

cpp 复制代码
f[n]=f[n-1]+f[n-2]

即在 后面放 ,在 后面放 。

现在假设增加一个 ,。

增加 同理,

发现转移的时候要控制两边的二项式,麻烦,考虑换成确定末尾 的状态。

即定义 表示长度为 的序列,最后的位为 。


推

等于

前面这玩意是个固定的系数!太好了,我们只用处理 。

化简一下,设 ,,也就是我们只用在意 的个数。


如果直接线性递推,时间复杂度 ,寄。

1.设计



2.代码

时间复杂度 。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

typedef long long LL;
const int N = 200;

LL n, P; int K;

struct Matrix {
	LL a[N][N];
	Matrix() {
		memset(a, 0, sizeof(a));
	}
};

LL C[N][N];

Matrix operator*(const Matrix& a, const Matrix& b) {
    Matrix c;
    for (int i = 0; i <= 2 * K + 1; i++) {
        for (int k = 0; k <= 2 * K + 1; k++) {
            LL aik = a.a[i][k];
            if (!aik) continue;
            for (int j = 0; j <= 2 * K + 1; j++) {
                c.a[i][j] += aik * b.a[k][j];
            }
        }
        for (int j = 0; j <= 2 * K + 1; j++) {
            c.a[i][j] %= P;
        }
    }
    return c;
}

Matrix q_pow(Matrix a, LL b) {
	Matrix c;
	for (int i = 0; i <= 2 * K + 1; i ++) {
		c.a[i][i] = 1;
	}
	while (b) {
		if (b & 1) {
			c = c * a;
		}
		a = a * a;
		b >>= 1;
	}
	return c;
}

void init() {
	memset(C, 0, sizeof(C));
	C[0][0] = 1;
	for (int i = 0; i <= K; i ++) {
		C[i][0] = C[i][i] = 1;
		for (int j = 1; j < i; j ++) {
			C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % P;
		}
	}
}

int main () {
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	int a, b;
	cin >> n >> a >> b >> P;
	K = a + b;
	
	init();
	
	Matrix m, x, res;
	x.a[0][0] = 1;
	for (int i = K + 1; i <= 2 * K + 1; i ++) {
		x.a[i][0] = 1;
	}
	
	for (int i = 0; i <= K; i ++) {
		m.a[i][i] = 1;
		m.a[i][i + K + 1] = 1;
	}
	for (int i = 0; i <= K; i ++) {
		for (int j = 0; j <= i; j ++) {
			m.a[i + K + 1][j] = C[i][j];
		}
	}
	
	
	res = q_pow(m, n - 1) * x;
	
	LL ans = 0;
    LL n_pow = 1; 

    for (int i = 0; i <= a; i ++) {
        LL S = (res.a[K - i][0] + res.a[2 * K + 1 - i][0]) % P;

        LL term = C[a][i] * n_pow % P;
        term = term * S % P;

        if ((a - i) & 1) {
            ans = (ans - term + P) % P;
        }
		else {
            ans = (ans + term) % P;
        }

        n_pow = n_pow * n % P;
    }

    cout << ans % P << "\n";
	
	return 0;
}
相关推荐
fpcc4 小时前
c++编程实践—堆和栈越界调试
c++
yi0114 小时前
LeetCode 219:存在重复元素 II——哈希表记录“最近一次出现的位置”
数据结构·人工智能·笔记·python·算法·leetcode·哈希表
weiabc6 小时前
MSYS2 UCRT64 + g++ C++ 中文输出乱码 完整全过程
c++
李日华大战鸡红6 小时前
FOC状态空间方程模型推导(学习记录)
python·学习·线性代数
灯澜忆梦7 小时前
【面向对象编程C++】| 基础语法
java·c++·算法
小蒋观天下7 小时前
专项方案:大场景港口AI安防、多干扰环境下的算法调优与落地实操
人工智能·深度学习·算法·安全·机器学习·计算机视觉·ai大模型
Evand J7 小时前
【电机滤波例程5】渐消因子自适应扩展卡尔曼滤波(EKF),MATLAB。PMSM负载突变下的状态估计。附下载链接
算法·matlab
H.莓飛7 小时前
【数据结构】二叉树_OJ题
linux·开发语言·数据结构·算法
好想像大佬一样能够ak所有8 小时前
Leetcode35.搜索插入位置
数据结构·算法·leetcode
aqiu1111118 小时前
【C++算法打怪专栏】LeetCode 165. 比较版本号(双指针与字符串流法)
c++·算法·leetcode