[loj3219]Iloczyny Fibonacciego
注意到
$$
\begin{array}{ll}F_{n+m}&=F_{0}F_{n+m-2}+F_{1}F_{n+m-1}\\&=F_{0}F_{n+m-2}+F_{1}(F_{n+m-2}+F_{n+m-3})\\&=F_{1}F_{n+m-3}+F_{2}F_{n+m-2}\\&...
\\&=F_{n-1}F_{m-1}+F_{n}F_{m}\end{array}
$$
将其移项,即$F_{n}F_{m}=F_{n+m}-F_{n-1}F_{m-1}=\sum_{i=0}^{\min(n,m)}(-1)^{i}F_{n+m-2i}$
根据后者,考虑差分,在$n+m$处打上$+1$、$|n-m|-2$处打上$(-1)^{\min(n,m)}$即可
可以用ntt实现,即得到$AB=\sum_{i=0}^{n+m}k_{i}F_{i}$,但并不满足斐波那契表示
对于$k_{i}<0$,将$k_{i+1}$和$k_{i+2}$分别减去/加上$k_{i}$,结合构造过程,即可保证$k_{i}\ge 0$
用二进制分解$k_{i}$,即仅考虑$k_{i}$最高若干位,每次将当前结果乘$2$并加上若干$F_{i}$
乘$2$也可以转化为加法,仅只需实现单点加,并对其分类讨论:
- 若$i$上初始为$0$且$i+1$上非$0$,则将$i+1$赋为$0$并对$i+2$递归
- 若$i$和$i+1$上初始为$0$且$i-1$上非$0$,则将$i-1$赋为$0$并对$i+1$递归
- 若$i$和$i-1,i+1$上初始均为$0$,则将$i$赋为$1$
- 若$i$上初始为$1$,则将$i$赋为$0$并对$i+1$和$i-2$递归
前三类以$1$的个数为势能分析即可,最后一类中$i+1$必然转化为第$1$类
关于$i-2$,可以每次清$0$并从高位到低位做单点加,即可认为这样递归是$O(1)$的
另外,归纳证明$\sum_{1\le i\le n,i\equiv n\pmod 2}F_{i}=F_{n+1}-1$,则$AB<F_{n+1}F_{m+1}<F_{n+m+2}$
时间复杂度为$O(n\log n)$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 typedef vector<int> vi; 5 const int N=1000010,mod=998244353; 6 int t,n,m,a[N],b[N],g[N],ans[N]; 7 ll f[N]; 8 int add(int x,int y){ 9 x+=y; 10 return (x<mod ? x : x-mod); 11 } 12 int qpow(int n,int m){ 13 int s=n,ans=1; 14 while (m){ 15 if (m&1)ans=(ll)ans*s%mod; 16 s=(ll)s*s%mod,m>>=1; 17 } 18 return ans; 19 } 20 namespace Poly{ 21 const int N=20; 22 int n,tn,w[N][1<<N],iw[N][1<<N]; 23 void init(int g){ 24 for(int i=0;i<N;i++){ 25 w[i][0]=iw[i][0]=1; 26 w[i][1]=qpow(g,(mod-1>>i+1)); 27 iw[i][1]=qpow(w[i][1],mod-2); 28 for(int j=2;j<(1<<i);j++){ 29 w[i][j]=(ll)w[i][1]*w[i][j-1]%mod; 30 iw[i][j]=(ll)iw[i][1]*iw[i][j-1]%mod; 31 } 32 } 33 } 34 void get_n(int m){ 35 n=1,tn=0; 36 while (n<m)n<<=1,tn++; 37 } 38 void dft(int *a){ 39 for(int i=n,t=0;i>1;i>>=1,t++){ 40 int *W=w[tn-t-1]; 41 for(int j=0;j<n;j+=i) 42 for(int k=0;k<(i>>1);k++){ 43 int x=a[j+k],y=a[j+k+(i>>1)]; 44 a[j+k]=add(x,y); 45 a[j+k+(i>>1)]=(ll)(x-y+mod)*W[k]%mod; 46 } 47 } 48 } 49 void idft(int *a){ 50 for(int i=2,t=0;i<=n;i<<=1,t++){ 51 int *W=iw[t]; 52 for(int j=0;j<n;j+=i) 53 for(int k=0;k<(i>>1);k++){ 54 int x=a[j+k],y=(ll)W[k]*a[j+k+(i>>1)]%mod; 55 a[j+k]=add(x,y),a[j+k+(i>>1)]=add(x,mod-y); 56 } 57 } 58 int inv=qpow(n,mod-2); 59 for(int i=0;i<n;i++)a[i]=(ll)inv*a[i]%mod; 60 } 61 vi mul(vi a,vi b,int ma,int mb,int m){ 62 if (ma<0)ma=a.size(); 63 if (mb<0)mb=b.size(); 64 if (m<0)m=ma+mb-1; 65 ma=min(ma,m),mb=min(mb,m); 66 get_n(ma+mb-1); 67 a.resize(n),b.resize(n); 68 for(int i=ma;i<n;i++)a[i]=0; 69 for(int i=mb;i<n;i++)b[i]=0; 70 dft(a.data()),dft(b.data()); 71 for(int i=0;i<n;i++)a[i]=(ll)a[i]*b[i]%mod; 72 idft(a.data()),a.resize(m); 73 return a; 74 } 75 }; 76 void add(int k){ 77 if (!ans[k]){ 78 if (ans[k+1])ans[k+1]=0,add(k+2); 79 else{ 80 if (ans[k-1])ans[k-1]=0,add(k+1); 81 else ans[k]=1; 82 } 83 } 84 else{ 85 ans[k]=0,add(k+1); 86 if (k>1)add(max(k-2,1)); 87 } 88 } 89 int main(){ 90 Poly::init(3); 91 scanf("%d",&t); 92 while (t--){ 93 scanf("%d",&n); 94 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 95 scanf("%d",&m); 96 for(int i=1;i<=m;i++)scanf("%d",&b[i]); 97 vi v1(n+1),v2(m+1),v3; 98 for(int i=0;i<=n;i++)v1[i]=a[i]; 99 for(int i=0;i<=m;i++)v2[i]=b[i]; 100 v3=Poly::mul(v1,v2,-1,-1,-1); 101 for(int i=0;i<=n+m;i++)f[i]=v3[i]; 102 103 for(int i=0;i<=n;i++)v1[i]=a[i]; 104 for(int i=0;i<=m;i++)v2[i]=((i&1) ? -b[i] : b[i]); 105 reverse(v2.begin(),v2.end()); 106 v3=Poly::mul(v1,v2,-1,-1,-1); 107 for(int i=m+2;i<=n+m;i++){ 108 if (v3[i]>(mod>>1))v3[i]-=mod; 109 f[i-m-2]+=v3[i]; 110 } 111 112 for(int i=0;i<=n;i++)v1[i]=((i&1) ? -a[i] : a[i]); 113 for(int i=0;i<=m;i++)v2[i]=b[i]; 114 reverse(v1.begin(),v1.end()); 115 v3=Poly::mul(v1,v2,-1,-1,-1); 116 for(int i=n+2;i<=n+m;i++){ 117 if (v3[i]>(mod>>1))v3[i]-=mod; 118 f[i-n-2]+=v3[i]; 119 } 120 121 for(int i=n+m;i>1;i--)f[i-2]-=f[i]; 122 for(int i=0;i<=n+m-2;i++) 123 if (f[i]<0)f[i+2]+=f[i],f[i+1]-=f[i],f[i]=0; 124 f[1]+=f[0],f[0]=0; 125 int s=n+m+5; 126 for(int i=1;i<=s;i++)ans[i]=0; 127 for(int i=39;i>=0;i--){ 128 for(int j=1;j<=s;j++)g[j]=ans[j],ans[j]=0; 129 for(int j=s;j;j--){ 130 if (g[j])add(j),add(j); 131 if ((j<=n+m)&&((f[j]>>i)&1))add(j); 132 } 133 } 134 while (!ans[s])s--; 135 printf("%d ",s); 136 for(int i=1;i<=s;i++)printf("%d ",ans[i]); 137 puts(""); 138 } 139 return 0; 140 }