[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 }
View Code

 

posted @ 2023-01-19 14:54  PYWBKTDA  阅读(31)  评论(0编辑  收藏  举报