HDU 2604 Queuing




HDU2604
: 本鶸第二道矩阵快速幂。

题意: 
n个人排队,f表示女,m表示男,包含子串fmf和fff为O队列,否则为E队列,求有多少个序列为E队列。

由于只求个数,按经验xjb找一下递推公式 :

用lm(n)表示n个人满足结果的个数,那么

1)如果最后一个是m,那么就不考虑他,lm(n)为前n-1的结果个数;

2)如果最后一个是f,并且是mmf,那么需要向前推3位,即lm(n-3);//不考虑fmf和fff

3)如果最后一个是f,并且是mff,那么需要再向前推一位到mmff才能满足结果,即lm(n-4);

所以lm(n)=lm(n-1)+lm(n-3)+lm(n-4)

不过题目提到要%M,猜一下无脑递推大概会TLE,按照1e17fibonacci的经验我们知道这个时候就需要矩阵加速来搞一下。

借一张神犇们的图说明一下矩阵的构造方法

矩阵和快速幂的知识可以参考这里

#include<cstdio>
#include<cstring>

struct matrix
{
    int s[4][4];
    matrix()
    {
        memset(s,0,sizeof(s));
    }
};
int n,mod,sq[4][4]={{0,0,0,1},{1,0,0,0},{1,1,0,0},{0,0,1,1}};
void lm00(int *a,int *b)
{
    for(int i=0;i<16;i++)
        a[i]=b[i];
}
matrix mult(int a[][4],int b[][4])
{
    matrix c;
    for(int i=0;i<4;i++)
        for(int j=0;j<4;j++)
        {
            for(int k=0;k<4;k++)
                c.s[i][j]=(c.s[i][j]+a[i][k]*b[k][j])%mod;
        }
        return c;
}
matrix lm(int m)
{
    matrix a;
    if(m==1)
    {
        lm00(&a.s[0][0],&sq[0][0]);
    }
    else
    {
        a=lm(m/2);
        a=mult(a.s,a.s);
        if(m&1)
            a=mult(a.s,sq);
    }
    return a;
}
int main()
{
    int ans=0;
    matrix s;
    while(~scanf("%d%d",&n,&mod))
    {
        s=lm(n-2);
        ans=0;
        for(int i=0;i<4;i++)
        {
            for(int j=0;j<4;j++)
            {
                ans=(ans+s.s[i][j])%mod;
            }
        }
        printf("%d
",ans);
    }
    return 0;
}


原文地址:https://www.cnblogs.com/gfvod/p/5548318.html