【NOI2013】向量内积
定义两个$d$维向量${A=[a_1,a_2....a_n]}$,${B=[b_1,b_2....b_n]}$的内积为其相对应维度的权值的乘积和:
$${\left \langle A,B \right \rangle= \sum _{i=1}^{d}a_i*b_i}$$
现在有$n$个$d$维向量,判断是否存在两个向量的内积为$k$的倍数${(2\leq k\leq 3)}$
我们考虑将$n$个$d$维的向量构成一个$n*d$的矩阵$A$,$A^{T}$为$A$的转置矩阵。
令矩阵${B=A*A^{t}}$,那么${B_{i,j}}$就表示了向量$i$,与向量$j$的内积。
直接判断内积的值即可。
但是这仅仅简化了题意,复杂度仍是${O(n^{2}d)}$,大概可以得到$50$分。
考虑$k=2$的情况(矩阵的取值均在模$2$的意义下进行讨论)
我们有一种经典的方法判定两个矩阵是否相等,我们只关心$0$元素是否存在。
令$C$为全$1$矩阵
在模$2$的意义下随机一个$1*n$的向量$X$。
根据矩阵乘法的结合律判断等式${X*A*A^{T}=X*C}$是否成立。
若是存在有一个元素不相同,表示对应列上出现了一个$0$向量,然后暴力寻找行的位置即可。
若是这一次没有找到,也许是根本就没有这样的向量或者是刚好在这个$X$向量的影响下判为了相等,多做几次,每次正确率约为$0.5$。
综合暴力至此可以得到$75$分。
考虑$k=3$的情况,为什么就不能像$k=2$的时候那样做了呢?
因为矩阵$B$中的元素可以是${{0,1,2}}$了,无法再和全$1$矩阵$C$比较。
想办法将$k=3$的情况转换为$k=2$的情况。
之所以不能像$k=2$做,是因为出现了结果为$2$的情况。
注意到一个性质:${2\equiv -1\left ( mod 3 \right )}$
因此,如果我们将矩乘之后的矩阵D的所有结果平方,那么C就能用全1矩阵了。
令${NEWA\left ( i,j \right )=D(i,j)^{2}}$
${\because NEWA\left ( i,j \right )=\sum _{k_1=1}^{d}\sum _{k_2=1}^{d}A(i,k_1)A(i,k_2)A(k1,j)A(k2,j)}$
你可以想象成可以把每一个$d$维向量$A$转化为了${d^{2}}$维向量$Z$,其中${Z_{(i-1)*d+j}=a_i*a_j (1\leq i,j\leq d)}$
${\therefore }$这个时候变成了${n*d^{2}}$的矩阵与${d^{2}*n}$的矩阵相乘。
之后的做法就与$k=2$的情况相同。
综合之前的分数可以获得$100$分
NOTICE:$k=3$的运算是在模$3$的意义下的,只是最后的结果平方之后的值只能为${{0,1}}$。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<vector> 5 #include<cstdlib> 6 #include<cmath> 7 #include<cstring> 8 #include<ctime> 9 using namespace std; 10 #define maxn 100100 11 #define maxd 310 12 #define llg long long 13 #define yyj(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout); 14 llg n,a[maxn][maxd],d,k; 15 llg X[maxn],NX[maxn]; 16 llg LX[maxn],Y[maxn],LY[maxn],T,g[maxn],l[maxn],r[maxn]; 17 llg D; 18 bool pd=false; 19 20 void init() 21 { 22 cin>>n>>d>>k; 23 for (llg i=1;i<=n;i++) 24 for (llg j=1;j<=d;j++) 25 { 26 scanf("%lld",&a[i][j]); 27 // at[j][i]=a[i][j]; 28 g[i]+=a[i][j]*a[i][j]; g[i]%=k; 29 } 30 } 31 32 void check(llg i,llg j) 33 { 34 llg sum=0; 35 for (llg p=1;p<=d;p++) sum+=a[i][p]*a[j][p]; 36 sum%=k; 37 if (sum==0) 38 { 39 if (i>j) swap(i,j); 40 printf("%lld %lld\n",i,j); 41 pd=true; 42 } 43 } 44 45 inline void solve2() 46 { 47 memset(LX,0,sizeof(LX)); memset(NX,0,sizeof(NX)); 48 llg tot=0; 49 for (llg i=1;i<=n;i++) X[i]=rand()%k,tot+=X[i],tot%=k; 50 for (llg i=1;i<=d;i++) 51 for (llg j=1;j<=n;j++) 52 NX[i]+=X[j]*a[j][i],NX[i]%=k; 53 for (llg i=1;i<=n;i++) 54 for (llg j=1;j<=d;j++) 55 LX[i]+=NX[j]*a[i][j],LX[i]%=k; 56 for (llg i=1;i<=n;i++) 57 if (LX[i]!=tot) 58 { 59 for (llg j=1;j<=n;j++) 60 if (i!=j) 61 { 62 if (pd) return ; 63 check(i,j); 64 } 65 } 66 } 67 68 void solve3() 69 { 70 memset(LX,0,sizeof(LX)); memset(NX,0,sizeof(NX)); 71 llg tot=0; 72 for (llg i=1;i<=n;i++) X[i]=rand()%k,tot+=X[i]; 73 tot%=k; 74 for (llg j=1;j<=n;j++) 75 for (llg i=1;i<=D;i++) NX[i]+=X[j]*a[j][l[i]]*a[j][r[i]]; 76 for (llg i=1;i<=n;i++) 77 { 78 for (llg j=1;j<=D;j++) LX[i]+=NX[j]*a[i][l[j]]*a[i][r[j]]; 79 LX[i]+=(1-g[i])*X[i]; LX[i]%=k; LX[i]+=k; 80 if (LX[i]%k!=tot) 81 { 82 for (llg j=1;j<=n;j++) 83 if (i!=j) 84 { 85 if (pd) return; 86 check(i,j); 87 } 88 llg he=1; 89 } 90 } 91 } 92 93 int main() 94 { 95 yyj("a"); 96 srand(time(NULL)); 97 init(); 98 if (k==2) 99 { 100 T=10; 101 while (T--) 102 { 103 solve2(); 104 if (pd) return 0; 105 } 106 } 107 else 108 { 109 T=1; 110 for (llg i=1;i<=n;i++) g[i]*=g[i],g[i]%=k; 111 D=d*d; 112 for (llg i=1;i<=D;i++) 113 { 114 llg t=(i%d==0)?i/d:i/d+1; 115 l[i]=t,r[i]=i-(t-1)*d; 116 } 117 while (T--) 118 { 119 solve3(); 120 if (pd) return 0; 121 } 122 } 123 if (!pd) cout<<"-1 -1"; 124 return 0; 125 }
HACK(若取全1矩阵C,但C的对角线均设为了0):
4 6 2 1 1 0 0 0 0 1 1 1 1 0 0 1 1 1 0 0 1 1 0 0 1 1 1
${A*A^{T}}$
0 0 0 1 0 0 1 0 0 1 0 0 1 0 0 0
全${1}$向量${X}$
1 1 1 1
${A*X*A^{t}}$
1 1 1 1
${C*X}$
1 1 1 1
将误判为相等。