FZU 1692 Key problem(构造矩阵+矩阵快速幂)

【题目链接】点击打开FZU 1692

【题意】:1 题目的意思是有n个人构成一个圈,每个人初始的有ai个苹果,现在做m次的游戏,每一次游戏过后第i个人能够增加R*A(i+n-1)%n+L*A(i+1)%n 个苹果(题目有错),问m轮游戏过后每个人的苹果数

【思路】:

根据题目的意思我们能够列出一轮过后每个人的苹果数

   a0 = a0+R*an-1+L*a1

   a1 = a1+R*a0+L*a2

   .............................

   an-1 = an-1+R*an-2+L*a0

3 根据第二条思路我们可以构造出如下的矩阵

   1 L 0 ...... R        a0         a0'

   R 1 L .........  *     a1         a1'

   ...................       ....      = ......

   ...........R 1 L      an-2       an-2'

   L ...........R 1      an-1       an-1'

4 那么根据3我们可以利用矩阵快速幂求出最后的答案,但是题目的n最大为100,m最大为10^9,那么每个case的时间复杂度为O(Logm*n^3),当n最大为100的时候是会TLE的

5 我们发现初始的矩阵里面,矩阵是一个循环同构的,就是说矩阵的每一行度能够从上一行推出,那么我们只要利用O(n^2)的时间求出第一行,然后我们在利用递推求出剩下的n-1行,那么总的时间复杂度为O(Logm*n^2)

代码:

/*
Problem id. FZU 1692
RunID: 631373
UserID: ACM_herongwei
Submit time: 2015-09-04 11:58:16
Language: C++
Length: 1806 Bytes.
Result: Accepted
*/

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;

typedef long long LL;
const int N=105;

int arr[N];
int n,m,L,R,MOD;

struct mut
{
    LL mat[N][N];
    mut()
    {
        memset(mat,0,sizeof(mat));
    }
    void init()
    {
        for(int i=0; i<n; ++i)
        {
            mat[i][(i+n-1)%n]=L;
            mat[i][i]=1;
            mat[i][(i+1)%n]=R;
        }
    }
};

mut multi(mut &a,mut &b)
{
    mut c;
    for(int i=0; i<n; ++i)
    {
        if(a.mat[0][i])
        {
            for(int j=0; j<n; ++j)
            {
                if(b.mat[i][j])
                {
                    c.mat[0][j]=(c.mat[0][j]+a.mat[0][i]*b.mat[i][j])%MOD;
                }
            }
        }
    }
    for(int i = 1; i < n; i ++)
    {
        c.mat[i][0] = c.mat[i - 1][n - 1];
        for(int j = 1; j <n; j ++)
            c.mat[i][j] = c.mat[i - 1][j - 1];
    }

    return c;
}
mut poww(mut unit, mut a,int n)
{
    while(n)
    {
        if(n&1) unit=multi(unit,a);
        a=multi(a,a);
        n>>=1;
    }
    return unit;
}

void solve()
{
    int ans=0;
    mut unit,a;
    scanf("%d %d %d %d %d",&n,&m,&R,&L,&MOD);
    for(int i=0; i<n; ++i)
    {
        scanf("%d",&arr[i]);
        unit.mat[i][i]=1;
    }
    a.init();
    unit=poww(unit,a,m);
    for(int i=0; i<n; ++i)
    {
        ans=0;
        for(int j=0; j<n; ++j)
        {
            if(unit.mat[i][j]&&arr[j])
                ans+=(unit.mat[i][j]*arr[j])%MOD;
        }
        if(i) printf(" ");
        printf("%d",ans%MOD);
    }
    puts("");
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        solve();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值