【矩阵乘法】[NOI2013]向量内积
题目描述
两个
现在有
输入格式
第一行包含
接下来
输出格式
包含两个整数,用空格隔开。
如果存在两个向量
若不存在这样的向量组合,则输出两个
样例一
input
3 5 2 1 0 1 0 1 1 1 0 1 0 0 1 0 1 1
output
2 3
explanation
限制与约定
测试点编号 | ||||
---|---|---|---|---|
1 | ||||
2 | ||||
3 | ||||
4 | ||||
5 | ||||
6 | ||||
7 | ||||
8 | ||||
9 | ||||
10 | ||||
11 | ||||
12 | ||||
13 | ||||
14 | ||||
15 | ||||
16 | ||||
17 | ||||
18 | ||||
19 | ||||
20 |
时间限制:
空间限制:
分析
注意:以下运算都在模k意义下
k=2
我们把这些向量看成一个
令
但是求出
我们令
如果
我们再随机找出一个列向量
然后比较
尽管有出错的概率,但是这个算法还是比较可靠的。
k=3
我们发现
所以,我们令
然后参考
代码
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 100000
#define MAXM 100
int n,d,k,a[MAXN+10][MAXM+10],s[MAXN+10],c[MAXM*MAXM+10],g[MAXN+10];
void Read(int &x){
char c;
while(c=getchar(),c!=EOF)
if(c>='0'&&c<='9'){
x=c-'0';
while(c=getchar(),c>='0'&&c<='9')
x=x*10+c-'0';
ungetc(c,stdin);
return;
}
}
int Get_id(int i,int j){
return (i-1)*d+j;
}
void read(){
Read(n),Read(d),Read(k);
int i,j;
for(i=1;i<=n;i++)
for(j=1;j<=d;j++){
Read(a[i][j]);
a[i][j]%=k;
s[i]+=a[i][j]*a[i][j];
}
for(i=1;i<=n;i++)
s[i]%=k;
}
void solve2(){
int i,j,k,sum;
for(i=1;i<=d;i++)
for(j=1;j<=n;j++)
c[i]^=a[j][i];
for(i=1;i<=n;i++)
for(j=1;j<=d;j++)
g[i]^=a[i][j]&c[j];
for(i=1;i<=n;i++)
if(g[i]!=(s[i]^((n-1)&1)))
break;
if(i>n){
puts("-1 -1");
return;
}
for(j=1;j<=n;j++)
if(i!=j){
sum=0;
for(k=1;k<=d;k++)
sum^=a[i][k]&a[j][k];
if(!sum)
break;
}
if(i>j)
swap(i,j);
printf("%d %d\n",i,j);
}
void solve3(){
int i,j,k,sum;
for(i=1;i<=d;i++)
for(j=1;j<=d;j++)
for(k=1;k<=n;k++)
c[Get_id(i,j)]+=a[k][i]*a[k][j];
for(i=d*d;i;i--)
c[i]%=3;
for(i=1;i<=n;i++)
for(j=1;j<=d;j++)
for(k=1;k<=d;k++)
g[i]+=a[i][j]*a[i][k]*c[Get_id(j,k)];
for(i=1;i<=n;i++)
if(g[i]%3!=((n-1)+s[i]*s[i])%3)
break;
if(i>n){
puts("-1 -1");
return;
}
for(j=1;j<=n;j++)
if(j!=i){
sum=0;
for(k=1;k<=d;k++)
sum=(sum+a[i][k]*a[j][k])%3;
if(!sum)
break;
}
if(i>j)
swap(i,j);
printf("%d %d\n",i,j);
}
int main()
{
read();
if(k==2)
solve2();
else
solve3();
}