CodeForces 1182E Product Oriented Recurrence 数列通项转化,矩阵快速幂处理数列递推,逆元,欧拉降幂等综合数论

文章目录

题意

定 义 f ( n ) = f ( n − 1 ) ⋅ f ( n − 2 ) ⋅ f ( n − 3 ) ⋅ c 2 n − 6 ( n ≥ 4 ) 。 给 定 n , f ( 1 ) , f ( 2 ) , f ( 3 ) 和 c , 求 f ( n ) 对 1 0 9 + 7 取 模 的 结 果 。 定义f(n)=f(n-1)⋅f(n-2)⋅f(n-3)⋅c^{2n-6} (n≥4)。 给定n,f(1),f(2),f(3)和c,求f(n)对10^9+7取模的结果。 f(n)=f(n1)f(n2)f(n3)c2n6(n4)nf(1)f(2)f(3)cf(n)109+7

题解

首先看到 c 2 n − 6 c^{2n-6} c2n6,它非常不优美,因此将它转化一下,
变成 c n × f ( n ) = c n − 1 × f ( n − 1 ) × c n − 2 × f ( n − 2 ) × c n − 3 × f ( n − 3 ) c^n\times f(n)=c^{n-1}\times f(n-1)\times c^{n-2}\times f(n-2)\times c^{n-3}\times f(n-3) cn×f(n)=cn1×f(n1)×cn2×f(n2)×cn3×f(n3).
哎呦,经过这一手高妙的变换,我们可以无视 c c c这个东西了.
接下去的问题是矩阵快速幂只能解决加和型递推,如何改造成乘积型递推呢?
f ( n ) f(n) f(n) f ( 1 ) f(1) f(1), f ( 2 ) f(2) f(2), f ( 3 ) f(3) f(3)代替!

1 1 1
1 0 0
0 1 0
0 0 1
此矩阵为转移矩阵.

矩阵快速幂可以处理出第一行的三个数字 k 1 k1 k1, k 2 k2 k2, k 3 k3 k3分别代表 f ( n ) f(n) f(n)是由多少个 f ( 1 ) f(1) f(1), f ( 2 ) f(2) f(2), f ( 3 ) f(3) f(3)相乘得到的.
接下来又有一个问题.矩阵乘法必定要取模,可是我们现在递推的内容是指数,直接取模是不相等的,又该如何解决呢?
styx大佬:欧拉降幂!
由于本题模数为质数,直接用欧拉降幂公式中的第一条即可解决.
此时 ϕ ( x ) = x − 1 \phi(x)=x-1 ϕ(x)=x1.
所以矩阵快速幂中的模数为 1 0 9 + 6 10^9+6 109+6,千万不要打错,不然你怎么调都调不出来.
乘出来之后要除以 c n c^n cn,这个大家都知道,上逆元就可以了.
好了,解决,代码如下.
结果因为好久没打代码了绿得不行,连快速幂都写错了,调了好久,呜呜呜.

#include<bits/stdc++.h> //Ithea Myse Valgulious
/*省略快读快写*/
using namespace std;
const int mod=1e9+7,l=4;
struct juzhen{
  ll a[105][105];
  void clearit() {
    memset(a,0,sizeof a);
    for (int i=1;i<=l;++i) a[i][i]=1;
  }
  juzhen operator *(const juzhen &r) {
    int i,j,k; juzhen ans;
    memset(ans.a,0,sizeof ans.a);
    for (i=1;i<=l;++i) 
      for (j=1;j<=l;++j) 
        for (k=1;k<=l;++k) 
          ans.a[i][j]=(ans.a[i][j]+a[i][k]*r.a[k][j]%(mod-1))%(mod-1);
    return ans;
  } 
  juzhen operator ^(ll b) {
    juzhen ans;
    ans.clearit();
    for (;b;b>>=1,*this=*this**this) if (b&1) ans=ans**this;
    return ans;
  }
  void print() {
    int i,j;
    for (i=1;i<=l;++i,pl) 
      for (j=1;j<=l;++j) printf("%d ",a[i][j]);
  }
};
ll kasumi(ll a,ll b=mod-2) { //快速幂没有第二个自变量即为求逆元
  ll ans=1;
  for (;b;b>>=1,a=a*a%mod) if (b&1) ans=ans*a%mod;
  return ans;
}
juzhen q;
int main() {
  ll n,f1,f2,f3,c;
  read(n),read(f1),read(f2),read(f3),read(c);
  f1=f1*c%mod,f2=f2*kasumi(c,2)%mod,f3=f3*kasumi(c,3)%mod;
  q.a[1][1]=q.a[1][2]=q.a[1][3]=1;
  q.a[2][1]=q.a[3][2]=q.a[4][3]=1;
  q=q^(n-3);
  ll lxy=kasumi(f1,q.a[1][3])*kasumi(f2,q.a[1][2])%mod*kasumi(f3,q.a[1][1])%mod;
  printf("%lld\n",lxy*kasumi(kasumi(c),n)%mod);
}

Thank you for reading.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值