bzoj4417: [Shoi2013]超级跳马

来源:互联网 发布:java file.getname 编辑:程序博客网 时间:2024/06/04 17:40

题意

自己看

题解

你就随便矩阵快速幂一下就可以了
首先这题不难想到一个nm的做法,就是保存奇数列和偶数列的答案
看看代码就懂了吧

#include<cstdio>#include<cstring>const int N=55;int f[N][2];//哪一行  0:奇数列    1:偶数列 int n,m;int main(){    scanf("%d%d",&n,&m);    memset(f,0,sizeof(f));    f[1][0]=1;int now=0;    for (int u=2;u<m;u++)    {        for (int i=1;i<=n;i++)        {            f[i][now^1]+=f[i-1][now]+f[i][now]+f[i+1][now];        }        now^=1;    }    printf("%d\n",f[n][now]+f[n-1][now]);    return 0;}

然后你就可以尝试构造一个矩阵,让他快速幂一下
方法有很多
着这里是吧相邻的两列放在一起快速幂
矩阵大小1*(2n)
1~n是奇数位的和 n+1~2*n是偶数位的和
然后大力推他由上一个状态怎么推过来。。

for (LL u=1;u<=n;u++)//先把前面的搞好    {        b.f[u][u]=1;        b.f[u+n][u]=1;        if (u>1) b.f[u+n][u-1]=1;        if (u<n) b.f[u+n][u+1]=1;    }    for (LL u=n+1;u<=2*n;u++)    {        b.f[u][u]++;        /*对应自己*/        b.f[u-n][u]++;        if (u+1<=2*n) b.f[u+1][u]++;        b.f[u][u]++;        if (u-1>n) b.f[u-1][u]++;        /*对应+1*/        if (u<2*n)        {            b.f[u-n+1][u]++;            b.f[u][u]++;            if (u+1<=2*n) b.f[u+1][u]++;            if (u+2<=2*n) b.f[u+2][u]++;        }        /*对应-1*/        if (u>n+1)        {            b.f[u][u]++;            b.f[u-n-1][u]++;            if (u-1>n) b.f[u-1][u]++;            if (u-2>n) b.f[u-2][u]++;        }    }

小于n位的情况是比较直观的
但是大于n的位就要要论一下了,因为他需要转移的状态在上一个矩阵没有直观地出现。。于是要手完一下

然后就快速幂一下就好了。
要注意n=1的情况,否则会WA(但是对拍时抄了一个人的代码,他的没判,对拍挂了,交上去A了,我也不知道为什么)

#include<cstdio>#include<cstdlib>#include<algorithm>#include<iostream>#include<cstring>using namespace std;typedef long long LL;const LL N=55;const LL MOD=30011;struct qt{    LL x,y;//大小     LL f[N*2][N*2];    friend qt operator * (qt a,qt b)    {        qt c;c.x=a.x;c.y=a.y;        memset(c.f,0,sizeof(c.f));        for (LL u=1;u<=a.x;u++)//行            for (LL i=1;i<=a.y;i++)//列                for (LL j=1;j<=a.y;j++)                     c.f[u][i]=(c.f[u][i]+(a.f[u][j]*b.f[j][i])%MOD)%MOD;        return c;    }};//矩阵 qt a;//初始矩阵 qt b;//拿来乘的矩阵 LL n,m; void prepare ()//构造初始矩阵 {    a.x=1;a.y=2*n;a.f[1][1]=1;a.f[1][n+1]=1;a.f[1][n+2]=1;    b.x=2*n;b.y=2*n;    for (LL u=1;u<=n;u++)//先把前面的搞好    {        b.f[u][u]=1;        b.f[u+n][u]=1;        if (u>1) b.f[u+n][u-1]=1;        if (u<n) b.f[u+n][u+1]=1;    }    for (LL u=n+1;u<=2*n;u++)    {        b.f[u][u]++;        /*对应自己*/        b.f[u-n][u]++;        if (u+1<=2*n) b.f[u+1][u]++;        b.f[u][u]++;        if (u-1>n) b.f[u-1][u]++;        /*对应+1*/        if (u<2*n)        {            b.f[u-n+1][u]++;            b.f[u][u]++;            if (u+1<=2*n) b.f[u+1][u]++;            if (u+2<=2*n) b.f[u+2][u]++;        }        /*对应-1*/        if (u>n+1)        {            b.f[u][u]++;            b.f[u-n-1][u]++;            if (u-1>n) b.f[u-1][u]++;            if (u-2>n) b.f[u-2][u]++;        }    }}qt shen (qt x,LL y){    /*printf("%d\n",y);    if (y==1) return x;    printf("YES\n");    qt lalal=shen(x,y/2);    lalal=lalal*lalal;    printf("NO");    if (y%2!=0) lalal=lalal*x;    return lalal;*/    qt ans;ans.x=x.x;ans.y=x.y;    for(int i=1;i<=ans.x;i++) ans.f[i][i]=1;    while(y)    {        if(y&1) ans=ans*x;        x=x*x;y>>=1;    }    return ans;}void solve (){    LL t=(m-2)/2;    a=a*shen(b,t);    if (m%2!=0)    {        if (n!=1)   printf("%lld\n",(a.f[1][n+n]+a.f[1][n+n-1])%MOD);        else printf("%lld\n",a.f[1][2*n]);    }    else    {        if (n!=1) printf("%lld\n",(a.f[1][n]+a.f[1][n-1])%MOD);        else printf("%lld\n",a.f[1][n]);    }}int main(){    scanf("%lld%lld",&n,&m);    prepare();    solve();    return 0;}
原创粉丝点击