hihoCoder1345 小h的朋友们

9 篇文章 0 订阅


描述

小h很多朋友。他给第i个朋友分配了一个代号Ai,并使代号序列满足如下关系:

A= (k* Ai-1 + k* Ai-2) mod 1,000,000,007

现在小h忘记了第z个朋友的代号Az,但是他记得第x个朋友和第y个朋友的代号Ax和Ay

小h很着急,向小y求助。小y很忙,把任务交给了你,希望你求出第z个朋友的代号。  

输入

第一行共2个整数,k1,k2

第二行共4个整数,x,y,Ax,Ay

第三行共1个整数,z。

3<=x,y,z<=1018   0<=k1,k2<=105

输入数据保证有解,且解唯一

输出

共一行1个整数,Az

样例输入
1 1
5 7 5 13
10
样例输出
55
这个题中文题意明显,给你个递推关系,给你第x项,第y项的值,求第z项的值。

xyz又那么大,明显矩阵快速幂。求第z项值就要知道初始的两个值才可以。那就是利用第x,y项来列方程求解了。

初始矩阵U为:   

   [ A1  A2]   

   [ 0    0]      

递推矩阵I为: 

  [ 0  k2] 

  [ 1  k1]

当然不唯一,保证递推关系成立就可以了

其实U的A2为当前值,这是第二个,那么 U×I^(x - 2) 得到x项矩阵,   U×I^(y-2)得到第y项矩阵,x,y项的值都知道了,乘一下列方程组

A1*x1 + A2*x2 = x

A1*y1 + A2*y2 = y

接下来消去一项求另一项,再带入求刚才消去的那一项。这个过程中的减法需要加mod再取模以免为负数,各种乘法都要乘一次取一次模,除法乘逆元,因为模的是指数,直接快速幂费马小定理求逆元。a^(p-2) = 1/a mod(p)。

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
const int N = 1000001;
typedef long long ll;
using namespace std;
int mod = 1000000007;
struct Mat
{
  ll a[2][2];
  Mat()
  {
    memset(a, 0, sizeof(a));
  }
  void set0()
  {
    memset(a, 0, sizeof(a));
  }
  void set1()
  {
    set0();
    for (int i = 0; i < 2; i++)
      a[i][i] = 1;
  }
  Mat operator * (const Mat& b)const
  {
    Mat c;
    c.set0();
    for (int i = 0; i < 2; i++)    
        for (int k = 0; k < 2; k++)
        if (a[i][k])
          for (int j = 0; j < 2; j++)
          {
            c.a[i][j] = ( (a[i][k]*b.a[k][j])%mod + c.a[i][j] ) % mod;
          }
     
      return c;
  }

};

Mat operator ^ (Mat a, ll x)
{
  Mat ret;
  ret.set1();

  while (x)
  {
    if (x&1)
      ret = ret * a;
    x >>= 1;
    a = a * a;
  }
  return ret;
}
ll Pow(ll a, ll x)
{
  ll ret = 1;
  a %= mod;
  while (x)
  {
    if (x&1)
      ret = (ret*a)%mod;
    x >>= 1;
    a = (a*a)%mod;
  }
  return ret;
}
int main()
{
    ll k1, k2;
    ll x, y, ax, ay, z;
    while (cin >> k1 >> k2)
    {
      cin >> x >> y >> ax >> ay >> z;

    
      Mat tx, ty, one;
   
      one.a[0][0] = 0;
      one.a[0][1] = k2;
      one.a[1][0] = 1;
      one.a[1][1] = k1;
      ty = one ^ (y - 2);
      tx = one ^ (x - 2);
      ll &x1 = tx.a[0][1], &x2 = tx.a[1][1], &y1 = ty.a[0][1], &y2 = ty.a[1][1];
      ll up = ((ax*y1%mod - x1*ay%mod) + mod)%mod;
      ll a2 = up * Pow(( (x2*y1 % mod - x1*y2 % mod) + mod)%mod, mod - 2) %mod;
      ll a1 = (ax - x2*a2%mod + mod)%mod;
      a1 = a1 * Pow(x1, mod - 2) %mod;
     
      Mat I;
      I.a[0][0] = a1;
      I.a[0][1] = a2;
      I = I * (one ^ (z - 2));
      cout<<I.a[0][1]<<endl;

    }

    return 0;
}



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值