【题解】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;
}
相关推荐
凤凰院凶涛QAQ27 分钟前
《Java版数据结构 & 集合类剖析》Map & Set & 反射:“从哈希碰撞到红黑树转换,反射帮你扒开 HashMap 的桶数组看个究竟”
java·数据结构·算法
w_zero_one2 小时前
算法--模拟
java·数据结构·算法
秋天的怀念_David3 小时前
算法一千零一夜 · 第十三夜 幻方,武侠世界里的数学迷宫
java·程序人生·算法
·present·3 小时前
CSAPP(lecture 4_01)
c语言·c++
FPGA小迷弟3 小时前
用 Claude Code 重构遗留系统:从评估到落地的完整实践指南
c++·python·ai·plotly·django·ai编程·claude
秋天的怀念_David3 小时前
算法一千零一夜 · 第十四夜 幻方与奇妙的二进制
java·程序人生·算法
薛定e的猫咪4 小时前
(ICLR 2020)MAML 靠的不是快速学习,而是特征复用
人工智能·深度学习·学习·算法·机器学习
程序员-King.4 小时前
【ROS1】Noetic 开发工作流程与常用命令
c++·ubuntu·ros
云深麋鹿4 小时前
C++ | 基于红黑树实现mymap与myset
开发语言·c++
薛定e的猫咪4 小时前
(ICLR 2026)DF-META:面向 FJSP 的无导数元学习实例自适应调度
人工智能·深度学习·学习·算法·机器学习