BZOJ 2396 - 神奇的矩陣
阿新 • • 發佈:2021-07-20
完蛋,下雨了。
目錄
。
。所以概率約為 \(\frac{1}{1000}\),為了保險可以多隨機幾次。
題目
題目大意
給出三個行數和列數均為 \(n\) 的矩陣 \(A,B,C\),判斷 \(AB=C\) 是否成立。
資料範圍與提示
\(n\le 1000\),矩陣中的數字大於等於 \(0\) 小於 \(1000\),資料組數不超過 \(5\) 組。
解法
隨機一個 \(n\times 1\) 的列向量 \(x\),我們 \(\mathcal O(n^2)\) 地判斷 \(ABx\) 是否與 \(Cx\) 相等。關於 \(ABx\) 可以運用乘法結合律先算出 \(D=Bx\),再算出 \(ABx=AD\)。
為啥捏?嘗試分析 \(P(AB\ne C\and ABx=Cx)\)
首先轉化一下 \(ABx=Cx\),發現滿足條件的 \(x\in \text{ker}(AB-C)\)。
而我們有結論:\(\text{rank}(A)+\text{dim}(\text{ker}(A))=n\)。因為 \(AB\ne C\),所以 \(\text{rank}(AB-C)\ge 1\),從而推出 \(\text{dim}(\text{ker}(A))\le n-1\)。
由此觀之,用 \(\text{ker}(AB-C)\) 組成子空間的維度至少比 \(V\) 的維度少 \(1\)。我們感性理解,從二維拓展到三維會使空間整點個數乘 \(t\)(其中 \(t\) 為值域包含整數個數),對於這道題大約就是 \(1000\)
程式碼
#include <cstdio> #define print(x,y) write(x),putchar(y) template <class T> inline T read(const T sample) { T x=0; int f=1; char s; while((s=getchar())>'9'||s<'0') if(s=='-') f=-1; while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar(); return x*f; } template <class T> inline void write(const T x) { if(x<0) return (void) (putchar('-'),write(-x)); if(x>9) write(x/10); putchar(x%10^48); } #include <ctime> #include <cstdlib> using namespace std; const int maxn=1005; int n,a[maxn][maxn],r[maxn]; int b[maxn][maxn],c[maxn][maxn]; int d[maxn]; int main() { srand(time(NULL)); while(scanf("%d",&n)!=EOF) { for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) a[i][j]=read(9); for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) b[i][j]=read(9); for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) c[i][j]=read(9); bool flag=0; for(int T=1;T<=10;++T) { for(int i=1;i<=n;++i) r[i]=rand(),d[i]=0; for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) d[i]+=b[i][j]*r[j]; for(int i=1;i<=n;++i) { int t1=0,t2=0; for(int j=1;j<=n;++j) t1+=a[i][j]*d[j], t2+=c[i][j]*r[j]; if(t1^t2) { flag=1; break; } } if(flag) break; } puts(flag?"No":"Yes"); } return 0; }