从线性代数角度看快速变换
考虑我们现在对两个幂级数 定义运算 :
假设 ,那么要求满足 ,现在给出 ,要求快速求出 。
于是我们考虑构造矩阵 满足 且 可逆,那么现在只需快速求出 即可。
不难发现当 为加法时我们的 即是系数表示法到点值表示法的转移矩阵。
现在考虑推导 进制 的系数矩阵:
不妨设 ,那么有
显然光靠这点是不够的,我们需要给 赋予更强的性质:假设当前有 个 进制位, ,我们构造记 表示 在 进制下的最高位, 表示 在 进制下的其余位,考虑矩阵乘法的式子:
于是现在如果求出了 ,我们可以利用分治法进行快速变换。
考虑之前推出的 元素之间的关系:
突然神似单位根反演???而且还要求有循环的意义,那么这启示我们定义
于是
例题:[清华集训2016]石家庄的工人阶级队伍比较坚强
代码:
#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
inline int read(){
int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
const int N=550000;
int m,t,mod,n,trans[15][15],pw[15];
typedef long long ll;
inline int add(int a,int b){return (a+=b)<mod?a:a-mod;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline void Add(int&a,int b){(a+=b)<mod?a:a-=mod;}
inline void Dec(int&a,int b){(a-=b)<0?a+=mod:a;}
inline void Mul(int&a,int b){a=(ll)a*b%mod;}
inline int ksm(int a,int p){int ret=1;for(;p;p>>=1,Mul(a,a))if(p&1)Mul(ret,a);return ret;}
struct cp{
int x,y;
cp(int x=0,int y=0):x(x),y(y){}
friend inline cp operator+(cp a,cp b){return cp(add(a.x,b.x),add(a.y,b.y));}
friend inline cp operator-(cp a,cp b){return cp(dec(a.x,b.x),dec(a.y,b.y));}
friend inline cp operator*(cp a,cp b){return cp(dec(mul(a.x,b.x),mul(a.y,b.y)),dec(add(mul(a.x,b.y),mul(a.y,b.x)),mul(a.y,b.y)));}
friend inline cp operator^(cp a,int p){cp ret=cp(1,0);for(;p;p>>=1,a=a*a)if(p&1)ret=ret*a;return ret;}
friend inline bool operator<(cp a,cp b){return a.x^b.x?a.x<b.x:a.y<b.y;}
}w[3],a[N],b[N];
map<cp,cp>S;
inline void exgcd(int a,int b,int&x,int&y){
if(!b){x=1,y=0;return;}
exgcd(b,a-a/b*b,x,y);
int t=x;
x=y,y=t-a/b*y;
}
inline int inv(int a){
int x,y,b=mod;
exgcd(a,b,x,y);
return (x%b+b)%b;
}
inline void dft(cp*a,int type){
cp a0,a1,a2;
for(ri i=1;i<n;i*=3){
for(ri j=0,len=i*3;j<n;j+=len){
for(ri k=0;k<i;++k){
a0=a[j+k],a1=a[j+k+i],a2=a[j+k+i*2];
a[j+k]=a0+a1+a2;
a[j+k+i]=a0+w[1]*a1+w[2]*a2;
a[j+k+i*2]=a0+w[1]*a2+w[2]*a1;
if(type==-1)swap(a[j+k+i],a[j+k+i*2]);
}
}
}
}
inline void dfs(int ps,int sta,int ct1,int ct2){
if(ps==m){b[sta].x=trans[ct1][ct2];return;}
dfs(ps+1,sta+(pw[ps]<<1),ct1,ct2+1);
dfs(ps+1,sta+pw[ps],ct1+1,ct2);
dfs(ps+1,sta,ct1,ct2);
}
inline cp get(cp a,int t){return S.count(a)?S[a]:S[a]=a^t;}
int main(){
#ifdef ldxcaicai
freopen("lx.in","r",stdin);
#endif
pw[0]=1;
m=read(),t=read(),mod=read();
w[0]=cp(1,0),w[1]=cp(0,1),w[2]=cp(mod-1,mod-1);
for(ri i=1;i<=m;++i)pw[i]=pw[i-1]*3;
n=pw[m];
for(ri i=0;i<n;++i)a[i].x=read();
for(ri i=0;i<=m;++i)for(ri j=0;i+j<=m;++j)trans[i][j]=read();
dfs(0,0,0,0);
dft(a,1),dft(b,1);
for(ri i=0;i<n;++i)a[i]=a[i]*get(b[i],t);
dft(a,-1);
for(ri iv=inv(n),i=0;i<n;++i)cout<<mul(a[i].x,iv)<<'\n';
return 0;
}
来源:https://blog.csdn.net/dreaming__ldx/article/details/100120453