zoukankan      html  css  js  c++  java
  • 【NOI2013】向量内积

    定义两个$d$维向量${A=[a_1,a_2....a_n]}$,${B=[b_1,b_2....b_n]}$的内积为其相对应维度的权值的乘积和:

    $${left langle A,B ight angle= sum _{i=1}^{d}a_i*b_i}$$

    现在有$n$个$d$维向量,判断是否存在两个向量的内积为$k$的倍数${(2leq kleq 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$的情况。

     注意到一个性质:${2equiv -1left ( mod  3 ight )}$

     因此,如果我们将矩乘之后的矩阵D的所有结果平方,那么C就能用全1矩阵了。

     令${NEWAleft ( i,j ight )=D(i,j)^{2}}$

     ${ecause NEWAleft ( i,j ight )=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 (1leq i,jleq d)}$

     ${ herefore }$这个时候变成了${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
    ",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 

    将误判为相等。

    本文作者:xrdog 作者博客:http://www.cnblogs.com/Dragon-Light/ 转载请注明出处,侵权必究,保留最终解释权!
  • 相关阅读:
    类的专有方法(__getitem__和__setitem__)
    类的专有方法(__len__)
    demo02
    python之函数用法__str__()
    repr
    类的专有方法(__repr__)
    类的专有方法(__del__)
    类的专有方法(__init__)
    静态方法
    Golang接口简单了解
  • 原文地址:https://www.cnblogs.com/Dragon-Light/p/6378185.html
Copyright © 2011-2022 走看看