FZU 1692 Key problem

FZU_1692

    首先感觉输入数据里面的L和R应该反过来读取即先读入R再读入L,要不然样例算不出来,不知道是不是我理解错题意了。

    矩阵不难构造,但这个题让进一步注意到了矩阵运算中的常熟优化:

    ①由于递推关系的矩阵各行是循环同构的,而两个这样的循环同构的矩阵的乘积依然是循环同构的,所以在用二分矩阵的方法计算的时候,可以先用O(N^2)的时间计算出第一行,再用O(N^2)的时间平移出下面各行的结果,这样每次做乘法的复杂度就由O(N^3)减少到了O(N^2)。

    ②矩阵乘法的multiply的函数最好使用引用传递传参,如果直接传参的话每次相当于把矩阵复制一遍,这样效率就比较低了。

#include<stdio.h>
#include<string.h>
#define MAXD 110
int N, M, L, R, D, a[MAXD];
struct Matrix
{
    int a[MAXD][MAXD];
    Matrix()
    {
        memset(a, 0, sizeof(a));
    }
    void init()
    {
        int i, j;
        for(i = 0; i < N; i ++)
            a[i][(i + N - 1) % N] = L, a[i][i] = 1, a[i][(i + 1) % N] = R;
    }
};
Matrix multiply(Matrix &x, Matrix &y)
{
    int i, j, k;
    Matrix z;
    for(k = 0; k < N; k ++)
        if(x.a[0][k])
        {
            for(j = 0; j < N; j ++)
                if(y.a[k][j])
            z.a[0][j] = (z.a[0][j] + (long long)x.a[0][k] * y.a[k][j]) % D;
        }
    for(i = 1; i < N; i ++)
    {
        z.a[i][0] = z.a[i - 1][N - 1];
        for(j = 1; j < N; j ++)
            z.a[i][j] = z.a[i - 1][j - 1];
    }
    return z;
}
Matrix powmod(Matrix unit, Matrix mat, int n)
{
    while(n)
    {
        if(n & 1)
            unit = multiply(mat, unit);
        n >>= 1;
        mat = multiply(mat, mat);
    }
    return unit;
}
void solve()
{
    int i, j, ans;
    Matrix unit, mat;
    scanf("%d%d%d%d%d", &N, &M, &R, &L, &D);
    for(i = 0; i < N; i ++)
    {
        scanf("%d", &a[i]);
        unit.a[i][i] = 1;
    }
    mat.init();
    unit = powmod(unit, mat, M);
    for(i = 0; i < N; i ++)
    {
        ans = 0;
        for(j = 0; j < N; j ++)
            if(unit.a[i][j] && a[j])
                ans = (ans + (long long)unit.a[i][j] * a[j]) % D;
        if(i)
            printf(" ");
        printf("%d", ans);
    }
    printf("\n");
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t --)
    {
        solve();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/staginner/p/2471017.html