bzoj 4000 [TJOI2015]棋盘 dp 矩乘

本文介绍了一种使用矩阵快速幂解决特定类型问题的方法,并通过一个具体的编程实例详细展示了如何实现这一算法。文中涉及状态压缩、矩阵乘法及快速幂运算等关键技术点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

逗比题面,毁我青春
行列编号从零开始。。。然后我以为那个点在最上面那排。。。
妈蛋那样要记两排状态!!!
点在中间那排的话记一排状态矩乘转移就行了。

#include <bits/stdc++.h>
using namespace std;
#define ui unsigned int
int n,m,p,K;
int a[4][7],able[71];
ui ans;
struct Matrix 
{
    ui w[71][71];
    void init()
    {
        memset(w,0,sizeof(w));
        for(int i=0;i<1<<m;i++)w[i][i]=1;
    }
}mat,tmp;
int poss(int x,int y)
{
    if(K+y<0||K+y>=p)return 0;
    return a[1+x][K+y];
}
void mul(Matrix &r1,Matrix &r2,Matrix &r3)
{
    memset(&tmp,0,sizeof(tmp));
    for(int k=0;k<1<<m;k++)
        for(int i=0;i<1<<m;i++)if(r2.w[i][k])
            for(int j=0;j<1<<m;j++)if(r3.w[k][j])
                tmp.w[i][j]=tmp.w[i][j]+r2.w[i][k]*r3.w[k][j];
    memcpy(r1.w,tmp.w,sizeof(r1.w));
}
Matrix qpow(Matrix x,int y)
{
    Matrix ret;ret.init();
    while(y)
    {
        if(y&1)mul(ret,ret,x);
        mul(x,x,x);y>>=1;
    }
    return ret;
}
int main()
{
    //freopen("tt.in","r",stdin);
    scanf("%d%d%d%d",&n,&m,&p,&K);
    for(int i=0;i<3;i++)
        for(int j=0;j<p;j++)
            scanf("%d",&a[i][j]);
    for(int i=0;i<1<<m;i++)
    {
        able[i]=1;
        for(int j=0;j<m;j++)if(i>>j&1)
            for(int k=0;k<m;k++)if((i>>k&1)&&k!=j)
                if(poss(0,k-j))able[i]=0;
    }
    for(int i=0;i<1<<m;i++)if(able[i])
        for(int j=0;j<1<<m;j++)if(able[j])
        {
            mat.w[i][j]=1;
            for(int k=0;k<m;k++)if(i>>k&1)
                for(int u=0;u<m;u++)if(j>>u&1)
                    if(poss(1,u-k)||poss(-1,k-u))
                        mat.w[i][j]=0;
        }
    mat=qpow(mat,n);
    for(int i=0;i<1<<m;i++)
        ans+=mat.w[0][i];
    printf("%u\n",ans);
    return 0;
}   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值