AtCoder s8pc_3_g
NaCly_Fish · · 题解
题目链接
答案就是 fibonacci 数列的
以下都将
当然这两个分式都要求是真分式,满足条件
根据 EI 的方法,两边同时对
注意,我们并不需要实际地求出
然后就是要求出
虽然看起来难以处理,但等式右边只需要保留到一次项。具体处理方法如下:
提取等式右边的
代码如下(也许你会问为什么这么久才补代码,因为 shaber 评测要求答案必须换行输出,之前想破脑袋都没想到是这个问题):
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define N 200003
#define p 998244353
#define ll long long
using namespace std;
int inv[N];
struct mat{
int a[2][2];
inline mat(){ memset(a,0,sizeof(a)); }
}A;
inline mat operator * (const mat& lhs,const mat& rhs){
mat res;
for(int i=0;i!=2;++i)
for(int j=0;j!=2;++j)
res.a[i][j] = ((ll)lhs.a[i][0]*rhs.a[0][j]+(ll)lhs.a[i][1]*rhs.a[1][j])%p;
return res;
}
inline mat power(mat a,ll t){
mat res = mat();
res.a[0][0] = res.a[1][1] = 1;
while(t){
if(t&1) res = res*a;
a = a*a;
t >>= 1;
}
return res;
}
int n,ans,c = 1;
ll m;
int f0,f1,g[N];
int main(){
A.a[0][0] = A.a[0][1] = A.a[1][0] = 1;
scanf("%d%lld",&n,&m);
if(m==1){
puts("1");
return 0;
}
A = power(A,m-2);
if(n==1){
printf("%d\n",(A.a[0][0]+A.a[0][1])%p);
return 0;
}
inv[1] = 1;
for(int i=2;i<=n;++i) inv[i] = -(ll)(p/i)*inv[p%i]%p;
--n,m = (m-1)%p;
g[0] = -1,g[1] = -3;
for(int i=2;i<n;++i) g[i] = (3ll*g[i-1]-g[i-2])%p;
for(int i=n-1;~i;--i){
ans = (ans+(ll)c*g[i])%p;
c = (ll)c*(m+n-i)%p*inv[n-i]%p;
}
f0 = (-2ll*g[n-1]+(n>=2?g[n-2]:0))%p;
f1 = -g[n-1];
ans = (ans+(ll)f0*(A.a[0][0]+A.a[0][1])+(ll)f1*(A.a[1][0]+A.a[1][1]))%p;
printf("%d\n",(ans+p)%p);
return 0;
}