zoukankan      html  css  js  c++  java
  • Timus 1746 Hyperrook

    题意:在一个n维坐标系中,坐标的范围是0到m - 1,如果两个点坐标只有一个维度的坐标不同则可以相互移动,给出p个点,问任意两个点之间路径为d的个数是多少,答案与p取模。


    解法:只需要考虑两个点之间不同的维度的个数,递推方程:f[i][j]表示第i步时维度不同个数为j的路径数,f[i][j] = f[i - 1][j - 1] + f[i - 1][j] + f[i - 1][j + 1],由于d的数据范围很大,用矩阵乘法来优化递推关系,当d为1时,用一个矩阵a[i][j]表示从i个维度不同个数点到j个维度不同个数点的路径数,矩阵a的d次幂就是d次移动后的状态。要用到矩阵的快速幂。


    代码:

    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    #include<string>
    #include<string.h>
    #include<math.h>
    #include<limits.h>
    #include<time.h>
    #include<stdlib.h>
    #include<map>
    #include<queue>
    #include<set>
    #include<stack>
    #include<vector>
    #define LL long long
    using namespace std;
    LL n, m, d, p, q;
    int point[55][55];
    LL ans[55][55], x[55][55];
    void mul(LL a[55][55], LL b[55][55])
    {
        LL tmp[55][55] = {0};
        for(int i = 0; i <= n; i++)
            for(int j = 0; j <= n; j++)
                for(int k = 0; k <= n; k++)
                {
                    tmp[i][j] += a[i][k] * b[k][j] % p;
                    tmp[i][j] %= p;
                }
        memcpy(a, tmp, sizeof(tmp));
        return ;
    }
    int main()
    {
        while(~scanf("%lld%lld%lld%lld%lld", &n, &m, &d, &p, &q))
        {
            for(int i = 0; i < q; i++)
                for(int j = 0; j < n; j++)
                    scanf("%d", &point[i][j]);
            memset(ans, 0, sizeof(ans));
            memset(x, 0, sizeof(x));
            for(LL i = 0; i <= n; i++)
            {
                if(i)
                    x[i - 1][i] = (n - i + 1) * (m - 1) % p;
                x[i][i] = i * (m - 2) % p;
                if(i < n)
                    x[i + 1][i] = (i + 1) % p;
            }
            for(int i = 0; i <= n; i++)
                ans[i][i] = 1;
            while(d)
            {
                if(d & 1)
                    mul(ans, x);
                d >>= 1;
                mul(x, x);
            }
            for(int i = 0; i < q; i++)
            {
                for(int j = 0; j < q; j++)
                {
                    int cnt = 0;
                    for(int k = 0; k < n; k++)
                        if(point[i][k] != point[j][k])
                            cnt++;
                    if(j) printf(" ");
                    printf("%lld", ans[cnt][0]);
                }
                puts("");
            }
        }
        return 0;
    }
    

    耶【什么鬼

  • 相关阅读:
    Java学习笔记(4)
    Idea常用功能汇总
    Java学习笔记(3)
    Java学习笔记(2)
    Java学习笔记(1)
    如何开发NPM包
    c#抓屏功能在DPI缩放后,截到的图片不完整的问题
    支持续传功能的ASP.NET WEB API文件下载服务
    ASP.NET MVC 阻止通过Url直接访问服务器上的静态文件
    VS2013/VS2015/VS2017通过oschina托管代码
  • 原文地址:https://www.cnblogs.com/Apro/p/4303983.html
Copyright © 2011-2022 走看看