题解:P7429 [THUPC 2017] 气氛
Edward2019 · · 题解
提供一个
首先结论是
然后考虑
首先根据 OEIS A003432,
我们可以把求体积过程中求向量的“减”改为“异或”,这样就是全
我们先
考虑下面这组数据:
1
4
1 0 1
0 0 1
1 1 1
0 1 1
0 1 0
“异或”上第一个向量后得到的四个向量是:
1 0 0
0 1 0
1 1 0
1 1 1
我们要求的就是分别去掉每一行后的行列式之和。这个形式有点像代数余子式,我们考虑给这个矩阵左边添上一列:
0 1 0 0
0 0 1 0
0 1 1 0
0 1 1 1
求一个方阵的所有代数余子式是可以做到
- 如果
\operatorname{rank}(A)<n-1 ,那么显然\operatorname{adj}(A)=0 。 - 如果
\operatorname{rank}(A)=n ,那么直接使用\operatorname{adj}(A)=\det(A)A^{-1} 求出伴随矩阵即可(不过这种情况显然本题中不会出现了)。
接下来就是
首先当
所以
因为
在本题中已经在左边添上了全零的一列,所以可以直接取
还有一些边界情况需要考虑,比如那个“对秩没有贡献的原矩阵行”是全
感觉我写得常数巨大,但还是获得了目前的最优解。以下代码经过了对拍,感觉应该没什么问题了:
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef long double ld;
const int N=40,mod=1e9+7,i2=5e8+4;
const ld eps=1e-12;
int T,n,a[N][N],b[N][N],w[N],ans,cnt;
ld A[N][N],c[N][N];
inline ld det(int n){
ld res=1;
for(int i=1;i<=n;i++){
int u=i;
for(int j=i+1;j<=n;j++)if(fabsl(A[j][i])>fabsl(A[u][i]))u=j;
if(fabsl(A[u][i])<eps)return 0;
if(u!=i)res*=-1,swap(A[i],A[u]);
res*=A[i][i];
for(int j=i+1;j<=n;j++){
const ld t=A[j][i]/A[i][i];
for(int k=i;k<=n;k++)A[j][k]-=A[i][k]*t;
}
}
return res;
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>T;
while(T--){
cin>>n,cnt=0,memset(w,0,sizeof(w));
for(int i=0;i<=n;i++)for(int j=1;j<n;j++)cin>>b[i][j];
memcpy(a,b,sizeof(b));
for(int i=1;i<=n;i++)for(int j=n-1;j;j--)a[i][j]^=a[0][j];
for(int i=1;i<n;i++)for(int j=1;j<n;j++)b[i][j]^=b[n][j],A[i][j]=b[i][j];
ans=(int)roundl(fabsl(det(n-1)))%mod;
for(int i=1;i<=n;i++)for(int j=n-1;j;j--)A[j][i]=a[i][j];
int useless=0;
for(int i=1,t=1;i<n&&t<=n;i++,t++){
int u;
while(t<=n){
u=i;
for(int j=i+1;j<n;j++)if(fabsl(A[j][t])>fabsl(A[u][t]))u=j;
if(fabsl(A[u][t])<eps)useless=t,t++;
else{cnt++;break;}
}
if(t>n)break;
if(u!=i)swap(A[i],A[u]);
for(int j=i+1;j<n;j++){
const ld d=A[j][t]/A[i][t];
for(int k=t;k<=n;k++)A[j][k]-=A[i][k]*d;
}
}
if(!useless)useless=n;
if(cnt==n-1){
for(int j=1;j<n;j++){
for(int i=1,t=0;i<=n;i++)if(i!=useless)c[j][++t]=a[i][j];
c[j][n]=a[useless][j];
}
for(int i=1;i<n;i++){
int u=i;
for(int j=i+1;j<n;j++)if(fabsl(c[j][i])>fabsl(c[u][i]))u=j;
if(u!=i)swap(c[i],c[u]);
for(int j=i+1;j<=n;j++)c[i][j]/=c[i][i];
c[i][i]=1;
for(int j=1;j<n;j++){
if(j==i)continue;
const ld t=c[j][i];
for(int k=i;k<=n;k++)c[j][k]-=c[i][k]*t;
}
}
ld v[N];
v[useless]=-1;
for(int i=1,t=0;i<=n;i++)if(i!=useless)t++,v[i]=c[t][n];
for(int i=1,t=0;i<=n;i++)if(i!=useless){
t++;
for(int j=1;j<n;j++)A[t][j]=a[i][j];
}
ld t=roundl(det(n-1));
for(int i=1;i<=n;i++)(ans+=llabs((int)roundl(fabsl(v[i]*t))))%=mod;
}
(ans*=i2)%=mod;
cout<<ans<<"\n";
}
return 0;
}