zoukankan      html  css  js  c++  java
  • 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^2mod 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
    ",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;
    }
    
    
  • 相关阅读:
    List集合之Vector分析
    List集合之ArrayList分析
    Linux下的tar压缩解压缩命令详解
    第五次会议(4.7)
    第四次会议(3.31)
    第三次会议(3.17)
    第二次会议(3.9)
    第一次会议(3.1)
    团队的Kick off
    Parse error: syntax error, unexpected T_ENDFOREACH in..报错处理
  • 原文地址:https://www.cnblogs.com/Yuzao/p/8593142.html
Copyright © 2011-2022 走看看