这道题目中D应该是<=100。。
我们可以把两个向量的点积看成1*d和d*1的矩阵相乘;那么我们将原始矩阵A转置得到A',A*A'[i,j]就是向量i*向量j的点积。
但是这样是O(N^2D)的;考虑用一些黑科技。考虑mod=2时,假设对于i,我们求出i之前的所有向量与i的点积的和;如果所有的点积都>0即=1,那么显然点积的和对二取模=(i-1)%2;否则如果≠(i-1)%2,显然i与i前面的某一个向量的点积=0,我们O(ND)寻找答案即可。但是这样不一定能得到解,我们不妨随机打乱向量的顺序然后判断,这样至少是1-(1/2)^5的正确率了。。
当mod=3时也是一样的,不过点积>0并不一定=1,但是注意到点积的平方>0则一定=1,把点积拆开来计算即可。
AC代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 100005
#define M 101
#define rd ((rand_now=((long long)rand_now*20000909+2010527)%1000000009)/97)
using namespace std;
int n,m,mod,rand_now=1000003,a[N][M],q[N],b[M],c[M][M];
int read(){
int x=0; char ch=getchar();
while (ch<'0' || ch>'9') ch=getchar();
while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
return x;
}
bool check(int x,int y){
int i,tmp=0;
for (i=1; i<=m; i++) tmp+=a[x][i]*a[y][i];
return !(tmp%mod);
}
int solve(int x){
int ans=0,i,j;
if (mod==2)
for (i=1; i<=m; b[i]^=a[x][i],i++)
ans^=b[i]&a[x][i];
else
for (i=1; i<=m; i++)
for (j=1; j<=m; c[i][j]+=a[x][i]*a[x][j],j++)
ans+=c[i][j]*a[x][i]*a[x][j];
return ans%mod;
}
int main(){
n=read(); m=read(); mod=read(); int i,j;
for (i=1; i<=n; i++)
for (j=1; j<=m; j++) a[i][j]=read()%mod;
for (i=1; i<=n; i++) q[i]=i;
int cas=7-mod;
while (cas--){
if (mod==2) memset(b,0,sizeof(b)); else memset(c,0,sizeof(c));
for (i=2; i<=n; i++) swap(q[i],q[rd%(i-1)+1]);
for (i=1; i<=n; i++) if (solve(q[i])!=(i-1)%mod)
for (j=1; j<i; j++) if (check(q[i],q[j])){
if (q[i]>q[j]) swap(i,j);
printf("%d %d\n",q[i],q[j]); return 0;
}
}
puts("-1 -1");
return 0;
}
by lych
2016.5.23