洛谷P4838 P哥破解密码【矩阵优化DP】

时空限制 1000ms / 512MB

题目描述

定义一个串合法,当且仅当串只由A和B构成,且没有连续的3个A。P哥知道,密码就是长度为N的合法字符串数量对1926081719260817取模的结果。但是P哥不会算,所以他只能把N告诉你,让你来算

至于为什么要对这个数取模,好像是因为纪念某个人,但到底是谁,P哥也不记得了
然而他忘记字符串长度N应该是多少了,于是他准备试M组数据。

输入格式:

第一行给出一个整数M表示询问次数
接下来M行每行给出一个正整数N,表示该组询问中字符串的长度

输出格式:

对于每一次询问输出一行一个整数表示答案

说明

对于100%的数据,满足 n , m ≤ 5 ∗ 1 0 4        l ≤ r ≤ m        k ≤ m        x ≤ 2 31 − 1 n,m\leq 5*10^4\;\;\;l\leq r\leq m\;\;\;k\leq m\;\;\;x\leq 2^{31}-1 n,m5104lrmkmx2311


题目分析

很久以前写的题了,最近突然发现变紫了。。。

d p [ i ] [ j ] dp[i][j] dp[i][j]表示当前字符串长度为 i i i,且末尾有连续 j j j个A的方案数
d p [ i ] [ 0 ] = d p [ i − 1 ] [ 0 ] + d p [ i − 1 ] [ 1 ] + d p [ i − 1 ] [ 2 ] dp[i][0]=dp[i-1][0]+dp[i-1][1]+dp[i-1][2] dp[i][0]=dp[i1][0]+dp[i1][1]+dp[i1][2]
d p [ i ] [ 1 ] = d p [ i − 1 ] [ 0 ] dp[i][1]=dp[i-1][0] dp[i][1]=dp[i1][0]
d p [ i ] [ 2 ] = d p [ i − 1 ] [ 1 ] dp[i][2]=dp[i-1][1] dp[i][2]=dp[i1][1]
方程是线性的所以矩乘优化就好

#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long lt;
#define lowbit(x) ((x)&(-x)) 

lt read()
{
    lt f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return x*f;
}

const lt mod=19260817;
lt n,q;

struct matrix
{
	lt mat[10][10],row,col;
	matrix(int r=0,int c=0){ 
		row=r; col=c; 
		for(int i=1;i<=row;++i)
		for(int j=1;j<=col;++j)
		mat[i][j]=0;
	}
};

matrix operator *(matrix a,matrix b){ 
	matrix c=matrix(a.row,b.col);
	for(int i=1;i<=a.row;++i)
	for(int j=1;j<=b.col;++j)
	for(int k=1;k<=a.col;++k)
	{
		c.mat[i][j]+=a.mat[i][k]*b.mat[k][j]%mod;
		c.mat[i][j]%=mod;
	}
	return c;
}

matrix qpow(matrix a,lt k)
{
	matrix res=matrix(a.row,a.col);
	for(int i=1;i<=a.row;++i) res.mat[i][i]=1;
	while(k){
		if(k&1) res=res*a;
		a=a*a; k>>=1;
	}
	return res;
}

int main()
{
    q=read();
    matrix f=matrix(1,3),h=matrix(3,3);
    f.mat[1][1]=f.mat[1][2]=1; f.mat[1][3]=0;
    
    h.mat[1][1]=1; h.mat[1][2]=1; h.mat[1][3]=0;
    h.mat[2][1]=1; h.mat[2][2]=0; h.mat[2][3]=1;
    h.mat[3][1]=1; h.mat[3][2]=0; h.mat[3][3]=0;
    
    while(q--)
    {
        n=read();
        matrix res=f*qpow(h,n-1);
        printf("%lld\n",(res.mat[1][1]+res.mat[1][2]+res.mat[1][3])%mod);
    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值