Codeforces 385E Bear in the Field(矩阵快速幂)

Source

Problem

一片 nn n ∗ n 的草莓地,每个位置的初始草莓量为横坐标和纵坐标之和。给出熊的初始位置 (sx,sy ( s x , s y ) ,以及初始移动速度 dx,dy) ( d x , d y ) ,求这头熊 t t 秒后的位置。每一秒会发生下列3件事:

  1. 速度增加k k k 为该位置的草莓数,即k=x+y)

    • 熊的位置发生移动, Xt=Xt1+DXt1+k X t = X t − 1 + D X t − 1 + k
    • 每个位置上草莓数 ++ + +
    • Solution

      题目中给出的线性关系很明显,就是要用矩阵快速幂。关键是怎么建立矩阵。

      XtYtDXtDYtt1=211100121100101000010100111110222211 Xt1Yt1DXt1DYt1t11  { X t Y t D X t D Y t t 1 } = { 2 1 1 0 1 2 1 2 0 1 1 2 1 1 1 0 1 2 1 1 0 1 1 2 0 0 0 0 1 1 0 0 0 0 0 1 }   ∗ { X t − 1 Y t − 1 D X t − 1 D Y t − 1 t − 1 1 }  

      上面那个矩阵比较坑的一点就是:题中所给的坐标是 [1,n] [ 1 , n ] ,计算时变成 [0,n1] [ 0 , n − 1 ] ,而 k=x+y k = x + y 要比正常情况少2( x1y1 x 少 1 , y 少 1 ),所以矩阵第六列的前四行都是2,而不是0。

      Code

      #include <bits/stdc++.h>
      using namespace std;
      
      typedef long long ll;
      typedef vector<ll> vec;
      typedef vector<vec>mat;
      
      ll n,sx,sy,dx,dy,t;
      
      mat mul(mat &A,mat &B,ll M)
      {
          mat C(A.size(),vec(B[0].size()));
          for(int i=0;i<A.size();++i){
              for(int k=0;k<B.size();++k){
                  for(int j=0;j<B[0].size();++j)
                      C[i][j]=(C[i][j]+A[i][k]%M*B[k][j]%M+M)%M;
              }
          }
          return C;
      }
      
      mat qpow(mat A,ll n,ll M)
      {
          mat B(A.size(),vec(A.size()));
          for(ll i=0;i<A.size();++i)
              B[i][i]=1;
          while(n>0){
              if(n&1) B=mul(B,A,M);
              A=mul(A,A,M);
              n>>=1;
          }
          return B;
      }
      
      int main()
      {
          scanf("%lld%lld%lld%lld%lld%lld",&n,&sx,&sy,&dx,&dy,&t);
          mat A(6,vec(6));
          mat B(6,vec(1));
      
          A[0][0]=A[1][1]=2;
          A[0][5]=A[1][5]=A[2][5]=A[3][5]=2;
          A[0][1]=A[0][2]=A[0][4]=A[1][0]=A[1][3]=A[1][4]=
          A[2][0]=A[2][1]=A[2][2]=A[2][4]=A[3][0]=A[3][1]=
          A[3][3]=A[3][4]=A[4][4]=A[4][5]=A[5][5]=1;
      
          B[0][0]=sx-1;B[1][0]=sy-1;B[2][0]=(dx+n)%n;
          B[3][0]=(dy+n)%n;B[4][0]=0;B[5][0]=1;
          A=qpow(A,t,n);
          B=mul(A,B,n);
          printf("%lld %lld\n",B[0][0]+1,B[1][0]+1);
          return 0;
      }
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值