FZU 1692 Key problem (构造矩阵)

题目链接:http://acm.fzu.edu.cn/problem.php?pid=1692

题意:n个小孩围城一圈,开始每个人有ai个苹果。接下来进行m轮分苹果。第t个人第i轮分得的苹果为R*x+L*y+z。x为第t左边的人上一次的苹果数,y为第t个人右边的人上一次的苹果数,z为第t个人本身拥有的苹果数。求m轮后每个人的苹果数。

思路:利用循环性,每次矩阵乘法的复杂度为O(n^2)。下面是一组测试数据计算初始矩阵(第一个矩阵)的1,2,3,4,5次方后的矩阵:

 

1 3 0 0 4
4 1 3 0 0
0 4 1 3 0
0 0 4 1 3
3 0 0 4 1

 

25 6 9 16 8
8 25 6 9 16
16 8 25 6 9
9 16 8 25 6
6 9 16 8 25

 

73 117 91 75 156
156 73 117 91 75
75 156 73 117 91
91 75 156 73 117
117 91 75 156 73

 

1009 700 742 972 673
673 1009 700 742 972
972 673 1009 700 742
742 972 673 1009 700
700 742 972 673 1009

 

int n,mod;

class Matrix
{
public:
    int a[N][N];

    void init(int x)
    {
        int i;
        if(!x) clr(a,0);
        else
        {
            clr(a,0);
            FOR0(i,N) a[i][i]=1;
        }
    }

    Matrix operator*(Matrix b)
    {
        int i,j,k,t;
        Matrix p;
        p.init(0);
        FOR0(i,n) FOR0(k,n)
        {
            (p.a[0][i]+=(i64)a[0][k]*b.a[k][i]%mod)%=mod;
        }
        FOR1(i,n-1) FOR0(j,n)
        {
            p.a[i][j]=p.a[i-1][(j+n-1)%n];
        }
        return p;
    }

    Matrix power(int t)
    {
        Matrix ans,p=*this;
        ans.init(1);
        while(t)
        {
            if(t&1) ans=ans*p;
            p=p*p;
            t>>=1;
        }
        return ans;
    }

    void print()
    {
        int i,j;
        FOR0(i,n)
        {
            FOR0(j,n) printf("%d ",a[i][j]);
            puts("");
        }
    }
};

Matrix a;
int m,L,R;
int data[N];

int main()
{
    rush()
    {
        RD(n,m);
        RD(L,R,mod);
        int i,l,r;
        a.init(1);
        FOR0(i,n)
        {
            l=(i+1)%n;
            r=(i+n-1)%n;
            a.a[i][i]=1;
            a.a[i][l]+=L%mod;
            a.a[i][r]+=R%mod;
        }
        a=a.power(m);
        FOR0(i,n) RD(data[i]);
        i64 ans,j;
        FOR0(i,n)
        {
            ans=0;
            FOR0(j,n) (ans+=(i64)a.a[i][j]*data[j]%mod)%=mod;
            printf("%d",ans);
            if(i<n-1) putchar(' ');
        }
        puts("");
    }
    return 0;
}

  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值