前置技能——求解递推式的通项公式
以二阶递推式 f n = a f n − 1 + b f n − 2 f_n=af_{n-1}+bf_{n-2} fn=afn−1+bfn−2 为例,做法如下(不会证明):
- 解出特征方程 x 2 = a x + b x^2=ax+b x2=ax+b 的两个根 x 1 , x 2 x_1,x_2 x1,x2。
- 设 f n = k 1 x 1 n + k 2 x 2 n f_n=k_1x_1^n+k_2x_2^n fn=k1x1n+k2x2n ,带入 f 0 = 1 , f 1 = 1 f_0=1,f_1=1 f0=1,f1=1 解出 k 1 , k 2 k_1,k_2 k1,k2,得到递推式。
本题解法
相当于求 ∑ i = 1 n ( f i K ) \sum_{i=1}^n {f_i\choose K} ∑i=1n(Kfi),把组合数用斯特林反演转化成求 ∑ i = 1 n f i K \sum_{i=1}^n f_i^K ∑i=1nfiK,然后利用通项公式和等比数列求和化简。注意通项公式中有根号,底数 a 可能不是 mod 的二次剩余,因此需要扩域,就是把一个数表示成 x + y a x+y\sqrt a x+ya。
// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define ll long long
#define ld long double
#define fir first
#define sec second
#define int ll
using namespace std;
const ll N=510,mod=998244353;
struct Gen {
ll x,y;
Gen (ll _x=0,ll _y=0) {x=_x,y=_y;}
};
ll O,S[N][N],C[N][N],fac[N];
inline int mns(int a,int b) {return ((a-b)%mod+mod)%mod;}
inline int add(int a,int b) {return (a+b)%mod;}
Gen operator * (Gen a,Gen b) {return Gen((1ll*a.x*b.x+1ll*a.y*b.y%mod*O%mod)%mod,(1ll*a.x*b.y+1ll*a.y*b.x)%mod);}
Gen operator * (Gen a,ll b) {return Gen(a.x*b%mod,a.y*b%mod);}
Gen operator + (Gen a,Gen b) {return Gen(add(a.x%mod,b.x%mod),add(a.y,b.y));}
bool operator == (Gen a,Gen b) {return a.x==b.x&&a.y==b.y;}
Gen qpow(Gen a,ll b)
{
Gen ans(1,0),base=a;
while(b)
{
if(b&1) ans=ans*base;
base=base*base;
b>>=1;
}
return ans;
}
ll qpow(ll a,ll b)
{
ll ans=1,base=a;
while(b)
{
if(b&1) ans=ans*base%mod;
base=base*base%mod;
b>>=1;
}
return (ans%mod+mod)%mod;
}
Gen operator - (Gen a,Gen b) {return Gen(mns(a.x,b.x),mns(a.y,b.y));}
Gen operator / (Gen a,Gen b) {return a*Gen(b.x,(mod-b.y+mod)%mod)*qpow(((1ll*b.x*b.x-1ll*b.y*b.y%mod*O%mod)%mod+mod)%mod,mod-2);}
ll read()
{
ll x=0,flag=1;char c=getchar();
while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();}
while(isdigit(c)) x=x*10+c-'0',c=getchar();
return x*flag;
}
signed main()
{
int T=read(),m=read(); Gen k1,k2,x1,x2;
if(m==2)
{
ll t=qpow(2,mod-2),s=qpow(10,mod-2);
O=5,x1=Gen(t,t),x2=Gen(t,mod-t),k1=Gen(t,s),k2=Gen(t,mod-s);
}
else
{
ll t=qpow(2,mod-2),s=qpow(6,mod-2);
O=3,x1=Gen(2,1),x2=Gen(2,mod-1),k1=Gen(t,s),k2=Gen(t,mod-s);
}
fac[0]=1; for(ll i=1;i<=502;i++) fac[i]=1ll*fac[i-1]*i%mod;
S[0][0]=1; for(ll i=1;i<=502;i++) for(ll j=1;j<=i;j++) S[i][j]=(S[i-1][j-1]-1ll*(i-1)*S[i-1][j])%mod;
for(int i=0;i<=502;i++) for(ll j=C[i][0]=1;j<=i;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
while(T--)
{
ll l,r,ksj=0; Gen ans(0,0); cin>>l>>r;ll k=read(); ll pl=l,pr=r;
if(m==3) l=l+1>>1,r=r/2;
for(ll j=0;j<=k;j++)
{
Gen t(0,0);
for(ll e=0;e<=j;e++)
{
Gen ss=qpow(x1,e)*qpow(x2,j-e),z;
if(ss==Gen(1,0)) z=qpow(k1,e)*qpow(k2,j-e)*qpow(ss,l)*((r-l+1)%mod);
else z=qpow(k1,e)*qpow(k2,j-e)*qpow(ss,l)*(Gen(1,0)-qpow(ss,r-l+1))/(Gen(1,0)-ss);
t=t+Gen(C[j][e],0)*z;
}
ans=ans+t*S[k][j];
}
ksj=ans.x%mod;
ksj=ksj*qpow(fac[k],mod-2)%mod*qpow((pr-pl+1)%mod,mod-2)%mod;
cout<<(ksj%mod+mod)%mod<<'\n';
}
return 0;
}