题目链接
题意
给定长度为 n 的序列 a,p,矩阵 A 由下列规则生成,求 det(A)mod(109+7)。
- A1,j=aj;
- ∀i>1,Ai,j=Ai−1,pj。
思路
观察到有一档部分分是置换 p 的环个数 >1,发现此时行列式值必为 0,证明可以分环数 =2 或 >2 讨论(>2 的时候可以消去最小的环转为子问题)。
对于只有一个环的情况,可以改为求循环矩阵行列式。
AξAξ=⎣⎢⎢⎢⎡a0an−1⋮a1a1a0⋮a2⋯⋯⋱⋯an−1an−2⋮a0⎦⎥⎥⎥⎤=⎣⎢⎢⎢⎡ωn0ωn1⋮ωnn−1⎦⎥⎥⎥⎤=⎣⎢⎢⎢⎡∑i=0n−1aiωni∑i=0n−1aiωni+1⋮∑i=0n−1aiωni+n−1⎦⎥⎥⎥⎤=(i=0∑n−1aiωni)ξ
即对于每个 n 阶复根 ωn,都有一个特征向量 ξ,它们线性无关,所以你就得到了 n 个特征值 ∑i=0n−1aiωni,它们的乘积就是 det(A)。
但是,在 mod(109+7) 意义下,有些 n 阶复根无法被整数表示,我们需要引入一种科技:把多项式 A 的所有零点代入多项式 B 并对函数值求积。
把多项式写成零点式,记 A=kA∏i=0n−1(x−si),B=kB∏i=0m−1(x−ti),则:
i=0∏n−1B(si)=i=0∏n−1kAj=0∏m−1(si−tj)=kAni=0∏n−1j=0∏m−1(si−tj)=(−1)nmkBmkAnj=0∏m−1kBi=0∏n−1(tj−si)=(−1)nmkBmkAni=0∏m−1A(ti)
这样就交换了 A 和 B 的地位。
而 B 显然可以对 A 取模,我们就可以做一个类似辗转相除的过程,把答案解出来。
在本题中,A=xn−1,B=∑i=0n−1aixi。
实现
直接使用暴力多项式取模即可,时间复杂度 O(n2)。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| #include<fstream> #include<algorithm> using namespace std; const int N=5000,mod=1e9+7; ifstream fin("matrix.in"); ofstream fout("matrix.out"); int n; int a[N+1],p[N+1]; int c,v[N+1]; int res; int pow(int x,int t) { int r=1; do { (t%2)&&(r=1ll*r*x%mod); } while(x=1ll*x*x%mod,t/=2); return r; } inline int inv(int x) { return pow(x,mod-2); } inline int ipow(int x,int t) { return pow(x,1ll*t*(mod-2)%(mod-1)); } struct poly { int n,a[N+1]; inline int &operator[](int x) { return a[x]; } inline int operator[](int x) const { return a[x]; } friend poly &operator%=(poly &x,const poly &y) { while(x.n>=y.n) { int w=1ll*x[x.n]*inv(y[y.n])%mod; for(int i=0;i<=y.n;++i) { x[x.n-i]=(x[x.n-i]-1ll*y[y.n-i]*w)%mod; } while(x.n&&!x[x.n]) { --x.n; } } return x; } friend inline void swap(poly &x,poly &y) { swap(x.n,y.n),swap(x.a,y.a); return; } } f,g; int main() { fin>>n; for(int i=1;i<=n;++i) { fin>>a[i]; } for(int i=1;i<=n;++i) { fin>>p[i]; } for(int i=1;v[++c]=(i=p[i]),i!=1;); if(c!=n) { res=0; goto output; } reverse(v+1,v+n+1); res=1; for(int i=1;i<n;++i) { for(int j=i+1;j<=n;++j) { if(v[i]>v[j]) { res=-res; } } } f.n=n-1; for(int i=1;i<=n;++i) { f[i-1]=a[v[i]]; } g.n=n,g[0]=-1,g[n]=1; while(f.n) { res=1ll*res*(f.n*g.n%2?-1:1)*pow(f[f.n],g.n)%mod*ipow(g[g.n],f.n)%mod; g%=f,swap(f,g); } res=1ll*res*pow(f[0],g.n)%mod; output: fout<<(res+mod)%mod<<endl; return 0; }
|