【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 

将误判为相等。

posted @ 2017-02-08 14:51  №〓→龙光←  阅读(1012)  评论(0编辑  收藏  举报