zoukankan      html  css  js  c++  java
  • 【BZOJ-2476】战场的数目 矩阵乘法 + 递推

    2476: 战场的数目

    Time Limit: 1 Sec  Memory Limit: 128 MB
    Submit: 58  Solved: 38
    [Submit][Status][Discuss]

    Description

    Input

    输入文件最多包含25组测试数据,每个数据仅包含一行,有一个整数p(1<=p<=109),表示战场的图形周长。p=0表示输入结束,你的程序不应当处理这一行。

    Output

    对于每组数据,输出仅一行,即满足条件的战场总数除以987654321的余数。

    Sample Input

    7
    8
    9
    10
    0

    Sample Output

    0
    2
    0
    9

    HINT

     湖南省第六届大学生计算机程序设计竞赛

    Source

    鸣谢刘汝佳先生授权使用

    Solution

    战场的定义比较趋近于俄罗斯方块,及不能有悬空的块;每个块下面必须为底或者是另一个块,并且这些块不能构成一个矩形。

    直接入手比较麻烦。

    很显然的就是高就是最高的块所在的层数,宽也是最后一层的宽度。

    分情况讨论一下,显然只有$p$为偶数的时候才可能有答案,奇数一定无解。

    1.如果左/右只有一边存在一个单独的块。

    这样删掉这个块将会得到周长为$p-2$时的一种方案。

    2.如果左/右都不存在单独一个块。

    这样无法通过删单个块得到一种周长为$p-2$的方案,但是,可以通过去掉最后一层得到一种周长为$p-2$的方案。

    3.如果左/右都存在一个单独的块。

    这种方案,会在情况1中额外统计,所以要减去,而这样的方案数则对应是周长为$p-4$时的方案。

    然后就可以得到递推式$f[p]=2*f[p-2]+f[p-2]-f[p-4]=3*f[p-2]-f[p-4]$

    然后这个显然是可以矩阵乘法优化的,不过这样会产生一些不必要的内存,所以我们把$p=p/2$然后就可以得到$f[p]=3*f[p-1]-f[p-2]$

    这样得到的答案,是满足的情况,是包含正好组成矩形的情况的,所以我们在最后把它减去即可。

    有一些小细节,稍微注意一下!

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    #define LL long long
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
        while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    #define P 987654321
    struct Matrix{int a[4][4]; Matrix() {memset(a,0,sizeof(a));}}A,B;
    int N,T;
    Matrix operator * (Matrix A,Matrix B)
    {
        Matrix C;
        for (int k=1; k<=3; k++)
            for (int i=1; i<=3; i++)
                if (A.a[i][k])
                    for (int j=1; j<=3; j++)
                        if (B.a[k][j])
                            C.a[i][j]=(C.a[i][j]+((LL)A.a[i][k]*B.a[k][j]+P)%P+P)%P;
        return C;
    }
    Matrix operator ^ (Matrix x,int k)
    {
        Matrix re; for (int i=1; i<=3; i++) re.a[i][i]=1;
        for (int i=k; i; i>>=1,x=x*x) if (i&1) re=re*x;
        return re;
    }
    int main()
    {    
        A.a[1][1]=3; A.a[1][2]=-1; A.a[1][3]=0;
        A.a[2][1]=1; A.a[2][2]=0; A.a[2][3]=0;
        A.a[3][1]=0; A.a[3][2]=1; A.a[3][3]=0;
        B.a[1][1]=13; B.a[2][1]=5; B.a[3][1]=0;
        while (1)
            {
                N=read(); if (!N) break;
                if (N&1 || N<8) {puts("0"); continue;}
                if (N==8) {puts("2"); continue;}
                if (N==10) {puts("9"); continue;}
                Matrix ANS; 
                ANS=A^(N/2-5); ANS=ANS*B;
    //            for (int i=1; i<=3; i++,puts(""))
    //                for (int j=1; j<=3; j++)
    //                    printf("%d  ",ANS.a[i][j]);
                printf("%d
    ",(ANS.a[1][1]-(N/2-1)+P)%P);
            }
        return 0;
    }

    又发了道水题,很惭愧....

  • 相关阅读:
    str_split — 将字符串转换为数组
    str_replace — 子字符串替换
    str_pad — 使用另一个字符串填充字符串为指定长度
    parse_str — 将字符串解析成多个变量
    number_format — 以千位分隔符方式格式化一个数字
    企业邮箱的优势有哪些?使用企业邮箱的好处
    TOM VIP邮箱,化繁为简,在微信里收发邮件
    邮箱办公神操作,让办公更自在,沟通无边界!
    常用的企业邮箱有哪些?企业邮箱有哪几种?
    外贸企业邮箱批发,收费企业邮箱与免费企业邮箱区别
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5946930.html
Copyright © 2011-2022 走看看