本人在写 CF53E 的时候,一眼秒掉了一个二项式反演+矩阵树定理的做法,结果求行列式用的是 double WA on test 11,改成剩余系下高消才过。
本题保证 n≤10,ai≤10,行列式的值不大于 nn−2=108,在这么小的范围下为什么 double 求行列式的值能够与正确值差几百?
代码:
double
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=20;
int work(double a[N][N],int n)
{
for(int i=1;i<=n;i++)
{
int d=0;
for(int j=1;j<=n;j++)
d+=a[i][j],a[i][j]=-a[i][j];
a[i][i]+=d;
}
n--;
double ans=1;
for(int i=1;i<=n;i++)
{
int Max=i;
for(int j=i+1;j<=n;j++)
if(abs(a[j][i])>abs(a[Max][i]))
Max=i;
if(abs(a[Max][i])<1e-8) return 0;
if(Max!=i) swap(a[Max],a[i]),ans=-ans;
ans*=a[i][i];
for(int j=i+1;j<=n;j++)
{
double t=a[j][i]/a[i][i];
for(int k=i;k<=n;k++) a[j][k]-=a[i][k]*t;
}
}
return ans;
}
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=20;
bool a[N][N];
const int mod=998244353;
int ksm(int a,int b)
{
int ans=1;
while(b)
{
if(b&1) ans=ans*a%mod;
a=a*a%mod,b>>=1;
}
return ans;
}
int work(int a[N][N],int n)
{
for(int i=1;i<=n;i++)
{
int d=0;
for(int j=1;j<=n;j++)
d+=a[i][j],a[i][j]=(mod-a[i][j])%mod;
a[i][i]+=d;
}
n--;
int ans=1;
for(int i=1;i<=n;i++)
{
int Max=i;
for(int j=i+1;j<=n;j++)
if(a[j][i]>a[Max][i])
Max=j;
if(!a[Max][i]) return 0;
if(Max!=i) swap(a[Max],a[i]),ans=mod-ans;
ans=ans*a[i][i]%mod;
for(int j=i+1;j<=n;j++)
{
int t=a[j][i]*ksm(a[i][i],mod-2)%mod;
for(int k=i;k<=n;k++) a[j][k]=(a[j][k]+mod-a[i][k]*t%mod)%mod;
}
}
return ans;
}