[2020-2021 集训队作业]Yet Another Linear Algebra Problem

壹、题目描述 ¶

传送门 to LOJ.

贰、题解 ¶


◆ 结论 !😃

第一问的答案为 \(\det(X^TX)\)​,第二问的答案为 \(\det(X^TA)\)​,其中 \(A_{i,j}\)​ 表示向量 \(\overrightarrow{v_i}\)​ 是否有颜色 \(j\)​.

要想到太难了,只能进行解释并加以理解......


◆ 爆切第一问 ~~~~>_<~~~~

第一问,其实就是求选出 \(m\) 个线性不相关的向量的方案数,可以考虑成,选出 \(m\) 个向量组成一个 \(m\times m\) 的矩阵,其行列式不为零的方案数。

但是这样似乎并不是很好解决,反而将问题复杂化,但是我们来看一看现在的问题是什么?

\[\sum_{i_1<i_2<...<i_m}[\det(X_{i_1}|X_{i_2}|\cdots|X_{i_m})\neq 0] \]

但是如果你足够熟悉,你会想到 \(\rm Binet-Cauchy\)​ 定理. 如果我们补上一个东西,那么就是:

\[\begin{aligned} &\sum_{i_1<i_2<...<i_m}[\det(X_{i_1}|X_{i_2}|\cdots|X_{i_m})\times \det(X^T_{i_1}|X^T_{i_2}|\cdots|X^T_{i_m})\neq 0] \\ \Leftrightarrow&\sum_{i_1<i_2<...<i_m}[\det(X_{i_1}|X_{i_2}|\cdots|X_{i_m})^2\neq 0] \end{aligned} \]

由于我们已知 \(1^2\equiv 2^2\equiv 1\pmod 3\)​,所以,原来不等于 \(0\) 的,后来也不会等于 \(0\),并且刚刚好为 \(1\) !那么,我们只需要算出它的值,得到的这个值就是最后的方案数!所以,我们继续反推:

\[\begin{aligned} &\sum_{i_1<i_2<...<i_m}[\det(X_{i_1}|X_{i_2}|\cdots|X_{i_m})^2\neq 0] \\ \Leftrightarrow &\sum_{i_1<i_2<...<i_m}\det(X_{i_1}|X_{i_2}|\cdots|X_{i_m})^2\pmod 3 \\ \Leftrightarrow &\sum_{i_1<i_2<...<i_m}\det(X^TX)^2\pmod 3 \\ \end{aligned} \]

为什么不是 \(\det(XX^T)\)​ ?因为乘出来的 \(\det\)​ 肯定为 \(0\)​.(它不满秩)


◆ 相似的第二问 😄

第二问比较相似,我们实际上需要满足两个条件 —— 选出来的 \(\overrightarrow{v_i}\) 并不是线性相关 + 颜色不重复。

而颜色不重复,如果我们按照上述定义 \(A\),事实上就是从 \(A\) 中选出的向量也不是线性相关的!

所以,我们将两个乘起来求行列式将会得到什么?

\[\begin{aligned} \det(X^TA)&=\sum_{i_1<i_2<...<i_m}\det(X^T_{i_1}|X^T_{i_2}|\cdots|X^T_{i_m})\times\det(A^T_{i_1}|A^T_{i_2}|\cdots|A^T_{i_m}) \pmod 2 \end{aligned} \]

如果不满足第一个条件,那么前面那一项将为 \(0\),如果不满足后面的条件,那么后面那一项将为 \(0\)​​​,所以,只有在两个同时不满足条件时,这一项才会有值,但这个 值一定是一个奇数?是的,它将一定会是一个奇数,并且值一定为 \(\pm 1\),在 \(\bmod 2\) 下即为 \(1\).

至于为什么 —— 每个元素中的值只有 \(0\) 或者 \(1\),如果它们是线性不相关的,那么最后一定会被消成一个单位矩阵,其行列式为 \(1\),算上交换行时的变号,便只有可能为 \(\pm 1\) 了。

叁、参考代码 ¶

#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;

#define NDEBUG
#include<cassert>

namespace Elaina{
    #define rep(i, l, r) for(int i=(l), i##_end_=(r); i<=i##_end_; ++i)
    #define drep(i, l, r) for(int i=(l), i##_end_=(r); i>=i##_end_; --i)
    #define fi first
    #define se second
    #define mp(a, b) make_pair(a, b)
    #define Endl putchar('\n')
    #define mmset(a, b) memset(a, b, sizeof a)
    // #define int long long
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    typedef pair<ll, ll> pll;
    template<class T>inline T fab(T x){ return x<0? -x: x; }
    template<class T>inline void getmin(T& x, const T rhs){ x=min(x, rhs); }
    template<class T>inline void getmax(T& x, const T rhs){ x=max(x, rhs); }
    template<class T>inline T readin(T x){
        x=0; int f=0; char c;
        while((c=getchar())<'0' || '9'<c) if(c=='-') f=1;
        for(x=(c^48); '0'<=(c=getchar()) && c<='9'; x=(x<<1)+(x<<3)+(c^48));
        return f? -x: x;
    }
    template<class T>inline void writc(T x, char s='\n'){
        static int fwri_sta[1005], fwri_ed=0;
        if(x<0) putchar('-'), x=-x;
        do fwri_sta[++fwri_ed]=x%10, x/=10; while(x);
        while(putchar(fwri_sta[fwri_ed--]^48), fwri_ed);
        putchar(s);
    }
}
using namespace Elaina;

const int maxn=500;

int n, m, Mod;

/**
 * @warning only available for class int or long long
*/
template<class T>struct matrix{
    int n, m;
    vector< vector<T> >a;
    inline matrix(){ n=m=0; a.clear(); }
    inline matrix(const int N, const int M, const T v=0): n(N), m(M){
        a=vector< vector<T> >(n);
        for(int i=0; i<n; ++i)
            a[i]=vector<T>(m, v);
    }
    inline matrix epsilon(const int N){ // switch
        (*this)=matrix(N, N, 0);
        for(int i=0; i<n; ++i) a[i][i]=1;
        return (*this);
    }
    inline matrix I(const int N){ // switch
        (*this)=matrix<T>(N, N, 1);
        return (*this);
    }
    inline matrix operator *(const matrix rhs) const{ // switch
        assert(m==rhs.n); matrix ret(n, rhs.m, 0);
        for(int i=0; i<n; ++i) for(int j=0; j<m; ++j) if(a[i][j])
            for(int k=0; k<rhs.m; ++k)
                ret.a[i][k]=(ret.a[i][k]+1ll*a[i][j]*rhs.a[j][k]%Mod)%Mod;
        return ret;
    }
    inline bool operator ==(const matrix rhs) const{
        if(n!=rhs.n || m!=rhs.m) return false;
        for(int i=0; i<n; ++i) for(int j=0; j<m; ++j)
            if(a[i][j]!=rhs.a[i][j])
                return false;
        return true;
    }
    inline matrix qkpow(ll power){
        assert(n==m);
        matrix<T>ret=(matrix<T>(n, n).epsilon(n)), a=(*this);
        for(; power; power>>=1, a=a*a)
            if(power&1) ret=ret*a;
        return ret;
    }
    inline bool operator !=(const matrix rhs) const{
        return !((*this)==rhs);
    }
    inline void print() const{
        printf("N == %d, M == %d\n", n, m);
        for(int i=0; i<n; ++i){
            for(int j=0; j<m; ++j)
                printf("%5d ", a[i][j]);
            Endl;
        }
    }
    inline int det(){
        assert(n==m); int ret=1;
        vector< vector<T> >Mat=a;
        for(int i=0; i<n; ++i){
            for(int j=i+1; j<n; ++j) while(Mat[j][i]){
                // assert(Mat[j][i]>0);
                int t=Mat[i][i]/Mat[j][i];
                for(int k=i; k<n; ++k)
                    Mat[i][k]=(Mat[i][k]+Mod-1ll*Mat[j][k]*t%Mod)%Mod;
                swap(Mat[i], Mat[j]), ret=-ret;
            }
            if(!Mat[i][i]) return 0;
            ret=1ll*ret*Mat[i][i]%Mod;
        }
        return (ret+Mod)%Mod;
    }
};

vector<int>v[maxn+5];
int c[maxn+5];

inline void input(){
    Mod=readin(1);
    if(Mod==1) Mod=3;
    n=readin(1), m=readin(1);
    if(Mod==3){
        for(int i=0; i<n; ++i){
            v[i].resize(m);
            for(int j=0; j<m; ++j)
                v[i][j]=readin(1);
        }
    }
    else{
        for(int i=0; i<n; ++i){
            v[i].resize(m);
            for(int j=0; j<m; ++j)
                v[i][j]=readin(1);
            c[i]=readin(1);
        }
    }
}

namespace task1{
    matrix<int>X, XT;
    inline void launch(){
        X=matrix<int>(n, m), XT=matrix<int>(m, n);
        for(int i=0; i<n; ++i) X.a[i]=v[i];
        for(int j=0; j<n; ++j) for(int i=0; i<m; ++i)
            XT.a[i][j]=v[j][i];
        writc((XT*X).det());
    }
}

namespace task2{
    matrix<int>XT, A;
    inline void launch(){
        XT=matrix<int>(m, n), A=matrix<int>(n, m);
        for(int j=0; j<n; ++j) for(int i=0; i<m; ++i)
            XT.a[i][j]=v[j][i];
        for(int i=0; i<n; ++i) A.a[i][c[i]-1]=1;
        writc((XT*A).det());
    }
}

signed main(){
    input();
    if(Mod==3) task1::launch();
    else task2::launch();
    return 0;
}

肆、关键之处 ¶

两个限制条件均为 “线性不相关”,考虑将其放到两个矩阵中,使用行列式时便可同时考虑到这两种情况。

posted @ 2021-07-22 20:17  Arextre  阅读(115)  评论(0编辑  收藏  举报