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;
}

原文地址:https://www.cnblogs.com/Yuzao/p/8593142.html