Loading [MathJax]/jax/output/CommonHTML/fonts/TeX/AMS-Regular.js

BZOJ5298 [CQOI2018] 交错序列 | 矩阵乘法和一个trick

题面

求所有长度为nn的、没有相邻的1的01序列中,若0有xx个、1有yy个,xaybxayb之和(对mm取模)。
n107,m108,0a,b45n107,m108,0a,b45

题解

本题麻烦的地方在于这个xaybxayb怎么处理。

xayb=(ny)ayb=ai=0Ciani(y)aiyb=ai=0(1)aiCianiya+bixayb=(ny)ayb=ai=0Ciani(y)aiyb=ai=0(1)aiCianiya+bi

所以可以求出对于所有i[0,a]i[0,a]yiyi之和,然后枚举ii乘上对应的系数,加起来即可。

那么如何求出yiyi之和呢?

f[k][i][0/1]f[k][i][0/1]表示长度为kk、结尾是0/1的序列中“1的个数”(即yy)的ii次方之和。

0结尾的序列可以从0/1序列转移过来,而1的出现次数不会变。

f[k][i][0]=f[k1][i][0]+f[k1][i][1]f[k][i][0]=f[k1][i][0]+f[k1][i][1]

1结尾的序列只能从0结尾的转移过来,1的出现次数会+1,也就是新的y=(y+1)i=ij=0Cjiy

f[k][i][1]=ij=0Cjif[k1][j][0]

然后构建矩阵就可以做了!

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <set>
#define enter putchar('\n')
#define space putchar(' ')
using namespace std;
typedef long long ll;
template <class T>
void read(T &x){
    char c;
    bool op = 0;
    while(c = getchar(), c < '0' || c > '9')
    if(c == '-') op = 1;
    x = c - '0';
    while(c = getchar(), c >= '0' && c <= '9')
    x = x * 10 + c - '0';
    if(op == 1) x = -x;
}
template <class T>
void write(T x){
    if(x < 0) putchar('-'), x = -x;
    if(x >= 10) write(x / 10);
    putchar('0' + x % 10);
}

const int N = 185;
int n, a, b, P, sze1, sze2;
ll c[N][N], ans;
struct matrix {
    ll g[N][N];
    matrix(){
	memset(g, 0, sizeof(g));
    }
    matrix operator * (const matrix &b) const {
	matrix c;
	for(int i = 0; i < sze2; i++)
	    for(int j = 0; j < sze2; j++){
		for(int k = 0; k < sze2; k++)
		    c.g[i][j] += g[i][k] * b.g[k][j];
		c.g[i][j] %= P;
	    }
	return c;
    }
    friend matrix qpow(matrix a, int x){
	matrix ret;
	for(int i = 0; i < sze2; i++)
	    ret.g[i][i] = 1;
	while(x){
	    if(x & 1) ret = ret * a;
	    a = a * a;
	    x >>= 1;
	}
	return ret;
    }
} op;

int main(){
    read(n), read(a), read(b), read(P);
    sze1 = a + b + 1, sze2 = 2 * sze1;
    c[0][0] = 1;
    for(int i = 1; i <= a + b; i++){
	c[i][0] = 1;
	for(int j = 1; j <= i; j++)
	    c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % P;
    }
    for(int i = 0; i < sze1; i++){
	op.g[i][i] = op.g[i][sze1 + i] = 1;
	for(int j = 0; j <= i; j++)
	    op.g[sze1 + i][j] = c[i][j];
    }
    op = qpow(op, n);
    ll pw = 1;
    for(int i = 0; i <= a; i++){
	ans += (((a - i) & 1) ? -1 : 1) * c[a][i] * pw % P * (op.g[a + b - i][0] + op.g[sze1 + a + b - i][0]) % P;
	pw = pw * n % P;
    }
    write((ans % P + P) % P), enter;
    return 0;
}
posted @   胡小兔  阅读(620)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示