【题解】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;
}
相关推荐
数模加油站1 小时前
26数模国赛C题|思路第3弹【顶流思路+深度攻略】
算法·数学建模·数学建模竞赛·国赛·26国赛
find1star1 小时前
LeetCode 25:K 个一组翻转链表
java·数据结构·算法·leetcode·链表·职场和发展·动态规划
光电笑映1 小时前
Linux 线程同步与互斥:锁的本质、条件变量与信号量的底层原理
linux·运维·服务器·开发语言·c++
jearry2 小时前
WebView2 原生拖放的桥接之道:拆解 yyzTools 的 drop-zone.js
前端·c++
零基础的修炼2 小时前
CUDA知识汇总
开发语言·c++·编辑器
欧特克_Glodon2 小时前
OpenCV计算机视觉开发入门与实践<三十八>:图像添加数字水印
c++·人工智能·opencv·计算机视觉
Bmob后端云2 小时前
Bmob后端云实战|Python给备忘录接入AI摘要、文本润色功能
算法·github
小鱼干..2 小时前
CTFHub技能树-ssrf-URL Bypass
算法
蒸蒸yyyyzwd2 小时前
与Redis和MySQL有关的知识
c++·求职招聘·八股