洛谷P5245 【模板】多项式快速幂

2021年09月16日 阅读数:3
这篇文章主要向大家介绍洛谷P5245 【模板】多项式快速幂,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

https://www.luogu.org/problemnew/show/P5245(常数项保证为1)html

https://www.luogu.org/problemnew/show/U63679   https://www.luogu.org/problemnew/show/P5273(常数项无限制,幂次<模数)数组

方法:$a^b=(e^{ln(a)})^b=e^{ln(a)b}$,多项式ln要求a的常数项为1,当a常数项为1时,这个过程能够直接对模数(998244353)取模(我不知道具体为何)ide

所以若是a的常数项为0,就“右移”直到常数项非0(设右移了k位),快速幂完了“左移”回去(要左移bk位)函数

(若是全部项都是0,那么快速幂以后答案必定仍为0,特判掉就好)url

若是常数项已经非0了但不是1,那么设常数项为k,$a^b=(\frac{a}{k}k)^b=(\frac{a}{k})^bk^b$,作法就是先全部项除以常数项,而后快速幂,最后全部项乘上$k^b$(注意最后这一步b若是要取模,就要对(phi(模数))(998244352)取模)spa

版本1:基于版本2,通常要求输入函数的b就是原始的b,没有取过模.net

  1 #prag\
  2 ma GCC optimize(2)
  3 #include<cstdio>
  4 #include<algorithm>
  5 #include<cstring>
  6 #include<vector>
  7 #include<cmath>
  8 using namespace std;
  9 #define fi first
 10 #define se second
 11 #define mp make_pair
 12 #define pb push_back
 13 typedef long long ll;
 14 typedef unsigned long long ull;
 15 const int md=998244353;
 16 const int N=262144;
 17 #define delto(a,b) ((a)-=(b),((a)<0)&&((a)+=md))
 18 inline int del(int a,int b)
 19 {
 20     a-=b;
 21     return a<0?a+md:a;
 22 }
 23 int rev[N];
 24 void init(int len)
 25 {
 26     int bit=0,i;
 27     while((1<<(bit+1))<=len)    ++bit;
 28     for(i=1;i<len;++i)
 29         rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
 30 }
 31 ull poww(ull a,ull b)
 32 {
 33     ull ans=1;
 34     for(;b;b>>=1,a=a*a%md)
 35         if(b&1)
 36             ans=ans*a%md;
 37     return ans;
 38 }
 39 int inv[300011];
 40 void dft(int *a,int len,int idx)//要求len为2的幂
 41 {
 42     int i,j,k,t1,t2;ull wn,wnk;
 43     for(i=0;i<len;++i)
 44         if(i<rev[i])
 45             swap(a[i],a[rev[i]]);
 46     for(i=1;i<len;i<<=1)
 47     {
 48         wn=poww(idx==1?3:332748118,(md-1)/(i<<1));
 49         for(j=0;j<len;j+=(i<<1))
 50         {
 51             wnk=1;
 52             for(k=j;k<j+i;++k,wnk=wnk*wn%md)
 53             {
 54                 t1=a[k];t2=a[k+i]*wnk%md;
 55                 a[k]+=t2;
 56                 (a[k]>=md)&&(a[k]-=md);
 57                 a[k+i]=t1-t2;
 58                 (a[k+i]<0)&&(a[k+i]+=md);
 59             }
 60         }
 61     }
 62     if(idx==-1)
 63     {
 64         ull ilen=inv[len];
 65         for(i=0;i<len;++i)
 66             a[i]=a[i]*ilen%md;
 67     }
 68 }
 69 void p_inv(int *f,int *g,int len)//g=f^(-1);f,g数组的长度不小于2len(须要足够长用于临时存放元素);要求len是2的幂
 70 {
 71     static int t1[N],t2[N];
 72     g[0]=poww(f[0],md-2);
 73     for(int i=2,j;i<=len;i<<=1)
 74     {
 75         memcpy(t1,f,sizeof(int)*i);
 76         memcpy(t2,g,sizeof(int)*(i>>1));
 77         memset(t2+(i>>1),0,sizeof(int)*(i>>1));
 78         init(i);
 79         dft(t1,i,1);dft(t2,i,1);
 80         for(j=0;j<i;++j)
 81             t1[j]=ull(t1[j])*t2[j]%md;
 82         dft(t1,i,-1);
 83         for(j=0;j<(i>>1);++j)
 84             t1[j]=t1[j+(i>>1)];
 85         memset(t1+(i>>1),0,sizeof(int)*(i>>1));
 86         dft(t1,i,1);
 87         for(j=0;j<i;++j)
 88             t1[j]=ull(t1[j])*t2[j]%md;
 89         dft(t1,i,-1);
 90         for(j=i>>1;j<i;++j)
 91             g[j]=md-t1[j-(i>>1)];
 92     }
 93 }
 94 inline void p_de(int *f,int len)//derivative求导;f=f'
 95 {
 96     for(int i=0;i<len-1;++i)
 97         f[i]=ull(i+1)*f[i+1]%md;
 98     f[len-1]=0;
 99 }
100 inline void p_in(int *f,int len)//integral积分;f=?f
101 {
102     for(int i=len-1;i>=1;--i)
103         f[i]=ull(f[i-1])*inv[i]%md;
104     f[0]=0;
105 }
106 void p_ln(int *f,int len)//要求len为2的幂,f[0]=1
107 {
108     static int t3[N];
109     p_inv(f,t3,len);p_de(f,len);
110     init(len<<1);
111     dft(f,len<<1,1);dft(t3,len<<1,1);
112     for(int i=0;i<(len<<1);++i)
113         f[i]=ull(f[i])*t3[i]%md;
114     dft(f,len<<1,-1);p_in(f,len);
115 }
116 void p_exp(int *f,int *g,int len)//要求len为2的幂,f[0]=0
117 {
118     static int t1[N],t2[N];
119     g[0]=1;
120     for(int i=2,j;i<=len;i<<=1)
121     {
122         memcpy(t1,g,sizeof(int)*(i>>1));
123         memset(t1+(i>>1),0,sizeof(int)*(i>>1));
124         p_ln(t1,i);
125         for(j=0;j<(i>>1);++j)
126             t1[j]=del(f[j+(i>>1)],t1[j+(i>>1)]);
127         memset(t1+(i>>1),0,sizeof(int)*(i>>1));
128         init(i);
129         dft(t1,i,1);
130         memcpy(t2,g,sizeof(int)*(i>>1));
131         memset(t2+(i>>1),0,sizeof(int)*(i>>1));
132         dft(t2,i,1);
133         for(j=0;j<i;++j)
134             t1[j]=ull(t1[j])*t2[j]%md;
135         dft(t1,i,-1);
136         for(j=i>>1;j<i;++j)
137             g[j]=t1[j-(i>>1)];
138     }
139 }
140 inline void p_pow_1(int *f,int *g,int len,int b)//要求len为2的幂,常数项为1
141 {
142     p_ln(f,len);
143     for(int i=0;i<len;++i)
144         f[i]=ull(f[i])*b%md;
145     p_exp(f,g,len);
146 }
147 void p_pow(int *f,int *g,int len,int b)//g=f^b;要求len为2的幂
148 {
149     int i;ll p=-1;
150     for(i=0;i<len;++i)
151         if(f[i])
152         {
153             p=i;
154             break;
155         }
156     if(p==-1)    return;
157     for(i=0;i<len-p;++i)
158         f[i]=f[i+p];
159     memset(f+len-p,0,sizeof(int)*p);
160     int t=f[0],t1=poww(t,md-2),t2=poww(t,b);
161     for(i=0;i<len;++i)
162         f[i]=ull(f[i])*t1%md;
163     p_pow_1(f,g,len,b);
164     for(i=0;i<len;++i)
165         g[i]=ull(g[i])*t2%md;
166     p*=b;
167     for(i=len-1;i>=p;--i)
168         g[i]=g[i-p];
169     memset(g,0,sizeof(int)*min(ll(len),p));
170 }
171 int a[N],b[N];
172 int n,n1,K;
173 int main()
174 {
175     int i,t;
176     inv[1]=1;
177     for(i=2;i<=300000;++i)
178         inv[i]=ull(md-md/i)*inv[md%i]%md;
179     scanf("%d",&n);n1=n;
180     char c;
181     for(c=getchar();c<'0'||c>'9';c=getchar());
182     for(;c>='0'&&c<='9';c=getchar())    K=(K*10LL+c-'0')%md;
183     for(i=0;i<n;++i)
184         scanf("%d",a+i);
185     for(t=1;t<n;t<<=1);
186     n=t;
187     p_pow(a,b,n,K);
188     for(i=0;i<n1;++i)
189         printf("%d ",b[i]);
190     return 0;
191 }
View Code

版本1.1:基于此题版本1,输入三个b分别表示对mod和mod-1取模的结果以及min(原始b,长度)code

这里能够交orzzzyhtm

  1 #prag\
  2 ma GCC optimize(2)
  3 #include<cstdio>
  4 #include<algorithm>
  5 #include<cstring>
  6 #include<vector>
  7 #include<cmath>
  8 using namespace std;
  9 #define fi first
 10 #define se second
 11 #define mp make_pair
 12 #define pb push_back
 13 typedef long long ll;
 14 typedef unsigned long long ull;
 15 const int md=998244353;
 16 const int N=2097152;
 17 #define delto(a,b) ((a)-=(b),((a)<0)&&((a)+=md))
 18 inline int del(int a,int b)
 19 {
 20     a-=b;
 21     return a<0?a+md:a;
 22 }
 23 int rev[N];
 24 void init(int len)
 25 {
 26     int bit=0,i;
 27     while((1<<(bit+1))<=len)    ++bit;
 28     for(i=1;i<len;++i)
 29         rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
 30 }
 31 ull poww(ull a,ull b)
 32 {
 33     ull ans=1;
 34     for(;b;b>>=1,a=a*a%md)
 35         if(b&1)
 36             ans=ans*a%md;
 37     return ans;
 38 }
 39 int inv[3000011];
 40 void dft(int *a,int len,int idx)//要求len为2的幂
 41 {
 42     int i,j,k,t1,t2;ull wn,wnk;
 43     for(i=0;i<len;++i)
 44         if(i<rev[i])
 45             swap(a[i],a[rev[i]]);
 46     for(i=1;i<len;i<<=1)
 47     {
 48         wn=poww(idx==1?3:332748118,(md-1)/(i<<1));
 49         for(j=0;j<len;j+=(i<<1))
 50         {
 51             wnk=1;
 52             for(k=j;k<j+i;++k,wnk=wnk*wn%md)
 53             {
 54                 t1=a[k];t2=a[k+i]*wnk%md;
 55                 a[k]+=t2;
 56                 (a[k]>=md)&&(a[k]-=md);
 57                 a[k+i]=t1-t2;
 58                 (a[k+i]<0)&&(a[k+i]+=md);
 59             }
 60         }
 61     }
 62     if(idx==-1)
 63     {
 64         ull ilen=inv[len];
 65         for(i=0;i<len;++i)
 66             a[i]=a[i]*ilen%md;
 67     }
 68 }
 69 void p_inv(int *f,int *g,int len)//g=f^(-1);f,g数组的长度不小于2len(须要足够长用于临时存放元素);要求len是2的幂
 70 {
 71     static int t1[N],t2[N];
 72     g[0]=poww(f[0],md-2);
 73     for(int i=2,j;i<=len;i<<=1)
 74     {
 75         memcpy(t1,f,sizeof(int)*i);
 76         memcpy(t2,g,sizeof(int)*(i>>1));
 77         memset(t2+(i>>1),0,sizeof(int)*(i>>1));
 78         init(i);
 79         dft(t1,i,1);dft(t2,i,1);
 80         for(j=0;j<i;++j)
 81             t1[j]=ull(t1[j])*t2[j]%md;
 82         dft(t1,i,-1);
 83         for(j=0;j<(i>>1);++j)
 84             t1[j]=t1[j+(i>>1)];
 85         memset(t1+(i>>1),0,sizeof(int)*(i>>1));
 86         dft(t1,i,1);
 87         for(j=0;j<i;++j)
 88             t1[j]=ull(t1[j])*t2[j]%md;
 89         dft(t1,i,-1);
 90         for(j=i>>1;j<i;++j)
 91             g[j]=md-t1[j-(i>>1)];
 92     }
 93 }
 94 inline void p_de(int *f,int len)//derivative求导;f=f'
 95 {
 96     for(int i=0;i<len-1;++i)
 97         f[i]=ull(i+1)*f[i+1]%md;
 98     f[len-1]=0;
 99 }
100 inline void p_in(int *f,int len)//integral积分;f=?f
101 {
102     for(int i=len-1;i>=1;--i)
103         f[i]=ull(f[i-1])*inv[i]%md;
104     f[0]=0;
105 }
106 void p_ln(int *f,int len)//要求len为2的幂,f[0]=1
107 {
108     static int t3[N];
109     p_inv(f,t3,len);p_de(f,len);
110     init(len<<1);
111     dft(f,len<<1,1);dft(t3,len<<1,1);
112     for(int i=0;i<(len<<1);++i)
113         f[i]=ull(f[i])*t3[i]%md;
114     dft(f,len<<1,-1);p_in(f,len);
115 }
116 void p_exp(int *f,int *g,int len)//要求len为2的幂,f[0]=0
117 {
118     static int t1[N],t2[N];
119     g[0]=1;
120     for(int i=2,j;i<=len;i<<=1)
121     {
122         memcpy(t1,g,sizeof(int)*(i>>1));
123         memset(t1+(i>>1),0,sizeof(int)*(i>>1));
124         p_ln(t1,i);
125         for(j=0;j<(i>>1);++j)
126             t1[j]=del(f[j+(i>>1)],t1[j+(i>>1)]);
127         memset(t1+(i>>1),0,sizeof(int)*(i>>1));
128         init(i);
129         dft(t1,i,1);
130         memcpy(t2,g,sizeof(int)*(i>>1));
131         memset(t2+(i>>1),0,sizeof(int)*(i>>1));
132         dft(t2,i,1);
133         for(j=0;j<i;++j)
134             t1[j]=ull(t1[j])*t2[j]%md;
135         dft(t1,i,-1);
136         for(j=i>>1;j<i;++j)
137             g[j]=t1[j-(i>>1)];
138     }
139 }
140 inline void p_pow_1(int *f,int *g,int len,int b)//要求len为2的幂,常数项为1
141 {
142     p_ln(f,len);
143     for(int i=0;i<len;++i)
144         f[i]=ull(f[i])*b%md;
145     p_exp(f,g,len);
146 }
147 void p_pow(int *f,int *g,int len,int b1,int b2,int b3)//g=f^b;要求len为2的幂
148 {
149     int i;ll p=-1;
150     for(i=0;i<len;++i)
151         if(f[i])
152         {
153             p=i;
154             break;
155         }
156     if(p==-1)    return;
157     for(i=0;i<len-p;++i)
158         f[i]=f[i+p];
159     memset(f+len-p,0,sizeof(int)*p);
160     int t=f[0],t1=poww(t,md-2),t2=poww(t,b2);
161     for(i=0;i<len;++i)
162         f[i]=ull(f[i])*t1%md;
163     p_pow_1(f,g,len,b1);
164     for(i=0;i<len;++i)
165         g[i]=ull(g[i])*t2%md;
166     p*=b3;
167     for(i=len-1;i>=p;--i)
168         g[i]=g[i-p];
169     memset(g,0,sizeof(int)*min(ll(len),p));
170 }
171 int a[N],b[N];
172 int n,n1,K1,K2;ll K3;
173 int main()
174 {
175     int i,t;
176     inv[1]=1;
177     for(i=2;i<=3000000;++i)
178         inv[i]=ull(md-md/i)*inv[md%i]%md;
179     scanf("%d",&n);n1=n;
180     char c;
181     for(c=getchar();c<'0'||c>'9';c=getchar());
182     for(;c>='0'&&c<='9';c=getchar())
183     {
184         K1=(K1*10LL+c-'0')%md;
185         K2=(K2*10LL+c-'0')%(md-1);
186         if(K3<=n)    K3=K3*10LL+c-'0';
187     }
188     K3=min(K3,ll(n));
189     for(i=0;i<n;++i)
190         scanf("%d",a+i);
191     for(t=1;t<n;t<<=1);
192     n=t;
193     p_pow(a,b,n,K1,K2,K3);
194     for(i=0;i<n1;++i)
195         printf("%d ",b[i]);
196     return 0;
197 }
View Code