0%

「2020-06-28 NOI 模拟赛」置换矩阵

题目链接

题意

给定长度为 nn 的序列 a,pa,p,矩阵 AA 由下列规则生成,求 det(A)mod(109+7)\det(A)\bmod(10^9+7)

  • A1,j=ajA_{1,j}=a_j
  • i>1,Ai,j=Ai1,pj\forall i>1,A_{i,j}=A_{i-1,p_j}

思路

观察到有一档部分分是置换 pp 的环个数 >1>1,发现此时行列式值必为 00,证明可以分环数 =2=2>2>2 讨论(>2>2 的时候可以消去最小的环转为子问题)。

对于只有一个环的情况,可以改为求循环矩阵行列式。

A=[a0a1an1an1a0an2a1a2a0]ξ=[ωn0ωn1ωnn1]Aξ=[i=0n1aiωnii=0n1aiωni+1i=0n1aiωni+n1]=(i=0n1aiωni)ξ\begin{aligned} A&=\begin{bmatrix}a_0&a_1&\cdots&a_{n-1}\\a_{n-1}&a_0&\cdots&a_{n-2}\\\vdots&\vdots&\ddots&\vdots\\a_1&a_2&\cdots&a_0\end{bmatrix}\\ \xi&=\begin{bmatrix}\omega_n^0\\\omega_n^1\\\vdots\\\omega_n^{n-1}\end{bmatrix}\\ A\xi&=\begin{bmatrix}\sum_{i=0}^{n-1}a_i\omega_n^i\\\sum_{i=0}^{n-1}a_i\omega_n^{i+1}\\\vdots\\\sum_{i=0}^{n-1}a_i\omega_n^{i+n-1}\end{bmatrix}\\ &=\left(\sum_{i=0}^{n-1}a_i\omega_n^i\right)\xi \end{aligned}

即对于每个 nn 阶复根 ωn\omega_n,都有一个特征向量 ξ\xi,它们线性无关,所以你就得到了 nn 个特征值 i=0n1aiωni\sum_{i=0}^{n-1}a_i\omega_n^i,它们的乘积就是 det(A)\det(A)

但是,在 mod(109+7)\bmod(10^9+7) 意义下,有些 nn 阶复根无法被整数表示,我们需要引入一种科技:把多项式 AA 的所有零点代入多项式 BB 并对函数值求积。

把多项式写成零点式,记 A=kAi=0n1(xsi)A=k_A\prod_{i=0}^{n-1}(x-s_i)B=kBi=0m1(xti)B=k_B\prod_{i=0}^{m-1}(x-t_i),则:

i=0n1B(si)=i=0n1kAj=0m1(sitj)=kAni=0n1j=0m1(sitj)=(1)nmkAnkBmj=0m1kBi=0n1(tjsi)=(1)nmkAnkBmi=0m1A(ti)\begin{aligned} \prod_{i=0}^{n-1}B(s_i)&=\prod_{i=0}^{n-1}k_A\prod_{j=0}^{m-1}(s_i-t_j)\\ &=k_A^n\prod_{i=0}^{n-1}\prod_{j=0}^{m-1}(s_i-t_j)\\ &=(-1)^{nm}\frac{k_A^n}{k_B^m}\prod_{j=0}^{m-1}k_B\prod_{i=0}^{n-1}(t_j-s_i)\\ &=(-1)^{nm}\frac{k_A^n}{k_B^m}\prod_{i=0}^{m-1}A(t_i) \end{aligned}

这样就交换了 AABB 的地位。
BB 显然可以对 AA 取模,我们就可以做一个类似辗转相除的过程,把答案解出来。

在本题中,A=xn1A=x^n-1B=i=0n1aixiB=\sum_{i=0}^{n-1}a_ix^i

实现

直接使用暴力多项式取模即可,时间复杂度 O(n2)\mathcal O(n^2)

代码

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;
}