bzoj 3243: [Noi2013]向量内积

Posted Boss.Pi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 3243: [Noi2013]向量内积相关的知识,希望对你有一定的参考价值。

Description

两个d 维向量A=[a1,a2,...,ad]与B=[b1,b2,...,bd]的内积为其相对应维度的权值的乘积和,即:
技术分享图片
现有 n 个d 维向量x1,...,xn ,小喵喵想知道是否存在两个向量的内积为k的倍数。请帮助她解决这个问题

Solution

首先做一个转换:如果把 \(B=A*A^T\) 构造出来,那么 \(B[i][j]\) 就代表向量 \(i\) 和向量 \(j\) 的内积,如果为 \(\mod k=0\) 则满足要求
\(A^T\) 是转置矩阵,也就是把原矩阵交换行列之后的矩阵

如果 \(k=2\)
我们只需要判断 \(A*A^T\) 是否和全 \(1\) 矩阵相等就行了
判断两个大矩阵相等一般用随机法:
随机一个行向量 \(E\),然后分别乘以两个矩阵判断行向量最后是否相等

行向量乘以矩阵的复杂度是 \(O(n*d)\) 的,所以复杂度就对了,在这个题利用矩乘的分配率 \(E*(A*A^T)=(E*A*)A^T\)
这样一次随机的正确性是 \(0.5\) 的(不会证),多随几次就可以了

\(k=3\)
由于矩阵中还有可能出现 \(2\) ,我们发现一个性质 \(2^2\mod 3=1\)
所以我们只需要把内积平方一下就可以了,即:
\((\sum_{i=1}^{d}a_i*b_i)*(\sum_{i=1}^{d}a_i*b_i)=\sum_{i=1}^{d}\sum_{j=1}^{d}a_i*b_i*a_j*b_j\)
相当于是构造出了一个大小为 \(n*d^2\) 的矩阵,还是像 \(k=2\) 那样做就可以了

#include<bits/stdc++.h>
using namespace std;
const int N=100010,M=110;
int a[N][M],n,m,mod,A[N],B[N],x[N],id[M][M];
inline void check(int x){
    for(int i=1;i<=n;i++){
        if(x==i)continue;
        int s=0;
        for(int j=1;j<=m;j++)s+=a[i][j]*a[x][j];
        s%=mod;
        if(!s)printf("%d %d\n",min(i,x),max(i,x)),exit(0);
    }
}
inline void solve(){
    int sum=0;
    for(int i=1;i<=n;i++)sum=(sum+(x[i]=rand()%mod))%mod;
    for(int i=1;i<=m;i++)A[i]=0;
    for(int i=1;i<=n;i++)B[i]=0;    
    for(int j=1;j<=n;j++)
        for(int i=1;i<=m;i++)A[i]+=x[j]*a[j][i];
    for(int i=1;i<=m;i++)A[i]%=mod;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)B[i]+=A[j]*a[i][j];
    for(int i=1;i<=n;i++)B[i]%=mod;
    for(int i=1;i<=n;i++)if(B[i]!=sum)check(i);
}
inline void solvet(){
    int sum=0,t=0;
    for(int i=1;i<=n;i++)sum=(sum+(x[i]=rand()%mod))%mod;
    for(int i=1;i<=n;i++)B[i]=0;
    for(int i=1;i<=m;i++)
        for(int j=1;j<=m;j++)A[id[i][j]=++t]=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            for(int k=1;k<=m;k++)A[id[j][k]]=(A[id[j][k]]+x[i]*a[i][j]*a[i][k])%mod;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            for(int k=1;k<=m;k++)B[i]=(B[i]+A[id[j][k]]*a[i][j]*a[i][k])%mod;
    for(int i=1;i<=n;i++)if(B[i]!=sum)check(i);
}
int main(){
  freopen("pp.in","r",stdin);
  freopen("pp.out","w",stdout);
  srand(time(NULL));
  scanf("%d%d%d",&n,&m,&mod);
  for(int i=1;i<=n;i++)
      for(int j=1;j<=m;j++)scanf("%d",&a[i][j]),a[i][j]%=mod;
  int T=7;
  while(T--)mod==2?solve():solvet();
  puts("-1 -1");
  return 0;
}

以上是关于bzoj 3243: [Noi2013]向量内积的主要内容,如果未能解决你的问题,请参考以下文章

[BZOJ]3243 向量内积(Noi2016)

[Noi2013]向量内积

uoj121 NOI2013—向量内积

P1224 [NOI2013] 向量内积(矩阵乘法&随机化)

[NOI2013]向量内积

线代线代复习自用