题目大意:
有数列:
fm,n=⎧⎩⎨⎪⎪an,n=1...m∑k=1m(a−1)fm,n−k−1(1)(1)fm,n={an,n=1...m∑k=1m(a−1)fm,n−k−1
求:hash=∑i=1mfi,nbaseihash=∑i=1mfi,nbasei。
其中:n≤1e9,m≤200n≤1e9,m≤200或n≤3e6,m≤1e9n≤3e6,m≤1e9
解题思路:
前一部分可以用特征多项式优化常系数线性递推做,主要是第二部分。
主要是要求m<nm<n的Fm,nFm,n,当m≥n,fm,nm≥n,fm,n都是anan,求hash直接等比数列求和即可。
注意如果把非正数项都看作0,除了fm,1、fm,m+1fm,1、fm,m+1,都有fm,n=afm,n−1−(a−1)fn−m−1,mfm,n=afm,n−1−(a−1)fn−m−1,m
考虑fmfm的生成函数Fm(x)=∑k=0∞fm,iFm(x)=∑k=0∞fm,i,根据上述特点,有:
F=axF−(a−1)xm+1F+ax−axm+1F=axF−(a−1)xm+1F+ax−axm+1(第1项少算了a,第m+1项多算了a,要特殊考虑)。
解得:
F=ax−axm+11−ax+(a−1)xm+1F=ax−axm+11−ax+(a−1)xm+1
由泰勒展开11−x=1+x+x2+x3+...11−x=1+x+x2+x3+...,所以有:
F=(ax−axm+1)∑k=0∞(ax+(1−a)xm+1)kF=(ax−axm+1)∑k=0∞(ax+(1−a)xm+1)k
不妨设G=∑k=0∞(ax+(1−a)xm+1)kG=∑k=0∞(ax+(1−a)xm+1)k,那么F=(ax−axm+1)GF=(ax−axm+1)G。
所以FF的n次方系数。
所以考虑如何求GG的n次方系数。
把GG用二项式展开:
直接枚举ii,那么,根据调和级数求和,对所有m<nm<n求Gm,nGm,n复杂度为O(nlogn)O(nlogn)。
完结撒花,贴上代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int getint()
{
int i=0,f=1;char c;
for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
if(c=='-')f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
const int N=3000005,M=505,mod=998244353,base=19260817;
int n,a;
struct Poly
{
ll a[M];int deg;
Poly(){memset(a,0,sizeof(a));}
inline friend Poly mul(const Poly &A,const Poly &B,const Poly &C)
{
Poly res;res.deg=A.deg+B.deg;
for(int i=0;i<=A.deg;i++)
for(int j=0;j<=B.deg;j++)
res.a[i+j]=(res.a[i+j]+A.a[i]*B.a[j])%mod;
for(int i=res.deg;i>=C.deg;i--)
for(int j=0;j<=C.deg;j++)
res.a[i-C.deg+j]=(res.a[i-C.deg+j]-res.a[i]*C.a[j])%mod;
res.deg=C.deg;
return res;
}
inline friend Poly Pow(Poly A,int b,const Poly &C)
{
Poly res;res.a[0]=1,res.deg=C.deg;
for(;b;b>>=1,A=mul(A,A,C))
if(b&1)res=mul(res,A,C);
return res;
}
};
int calc(int m)
{
Poly A,B,C;
A.a[0]=B.a[1]=C.a[m]=1;
A.deg=B.deg=C.deg=m;
for(int i=1;i<=m;i++)A.a[i]=A.a[i-1]*a%mod;
if(n<=m)return A.a[n];
for(int i=0;i<m;i++)C.a[i]=1-a;
B=Pow(B,n-1,C);
int res=0;
for(int i=0;i<m;i++)res=(res+B.a[i]*A.a[i+1])%mod;
return (res+mod)%mod;
}
void solve1(int m)
{
ll ans=0,bs=1,g;
for(int i=1;i<=m;i++)
{
bs=bs*base%mod;
g=calc(i);
ans=(ans+g*bs)%mod;
}
printf("%d\n",ans);
}
ll fac[N],fac_inv[N],bin1[N],bin2[N];
int Pow(ll x,int y)
{
ll res=1;
for(;y;y>>=1,x=x*x%mod)
if(y&1)res=res*x%mod;
return res;
}
int C(int x,int y){return fac[x]*fac_inv[y]%mod*fac_inv[x-y]%mod;}
int G(int m,int n)
{
ll res=0;
for(int i=0;i*m<=n;i++)
{
int k=n-i*m;
if(k<i)continue;
res=(res+bin1[k-i]*bin2[i]%mod*C(k,i))%mod;
}
return res;
}
void solve2(int m)
{
ll g,bs=1,ans=0;
fac[0]=bin1[0]=bin2[0]=1;
for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%mod;
for(int i=1;i<=n;i++)bin1[i]=bin1[i-1]*a%mod;
for(int i=1;i<=n;i++)bin2[i]=bin2[i-1]*(1-a+mod)%mod;
fac_inv[n]=Pow(fac[n],mod-2);
for(int i=n-1;i>=0;i--)fac_inv[i]=fac_inv[i+1]*(i+1)%mod;
for(int i=1;i<n&&i<=m;i++)
{
bs=bs*base%mod,g=(ll)a*(G(i,n-1)-G(i,n-i-1)+mod)%mod;
ans=(ans+g*bs)%mod;
}
if(n<=m)
{
bs=bs*base%mod;
g=bs*(Pow(base,m-n+1)-1)%mod*Pow(base-1,mod-2)%mod;
ans=(ans+bin1[n]*g)%mod;
}
printf("%d\n",ans);
}
int main()
{
//freopen("lx.in","r",stdin);
int m=getint();a=getint(),n=getint();
if(m<=200)solve1(m);
else solve2(m);
return 0;
}