题目描述
两个
d
维向量
现在有
n
个
输入格式
第一行包含
接下来
n
行每行有
输出格式
包含两个整数,用空格隔开。
如果存在两个向量
xp,xq
的内积为
k
的整数倍,则输出两个向量的编号
若不存在这样的向量组合,则输出两个 −1 。
样例一
input
3 5 2 1 0 1 0 1 1 1 0 1 0 0 1 0 1 1
output
2 3
explanation
⟨x1,x2⟩=1 , ⟨x1,x3⟩=1 , ⟨x2,x3⟩=2 。
限制与约定
测试点编号 | n | k | ||
---|---|---|---|---|
1 | 2 | 2 | ||
2 | 5 | 2 | ||
3 | 10 | 20 | 3 | |
4 | 20 | 20 | 2 | |
5 | 50 | 20 | 3 | |
6 | 50 | 50 | 2 | |
7 | 50 | 50 | 3 | |
8 | 80 | 80 | 2 | |
9 | 100 | 100 | 3 | |
10 | 500 | 100 | 3 | |
11 | 1000 | 100 | 2 | |
12 | 1000 | 100 | 3 | |
13 | 10000 | 100 | 2 | |
14 | 10000 | 100 | 3 | |
15 | 15000 | 100 | 2 | |
16 | 18000 | 100 | 2 | |
17 | 20000 | 100 | 2 | |
18 | 50000 | 30 | 3 | |
19 | 80000 | 30 | 3 | |
20 | 100000 | 30 | 3 |
时间限制: 5s
空间限制: 256MB
分析
注意:以下运算都在模k意义下
k=2
我们把这些向量看成一个
n×d
的矩阵
A
A 的转置矩阵
令
B=A×AT
,那么
bi,j
就表示
xi⋅xj
,如果
B
矩阵除了主对角线全部是1的话,显然无解。
但是求出
我们令
B′
为
bi,i=xi⋅xi
,其余元素为1的矩阵。
如果
B
=
我们再随机找出一个列向量
C
(其实就是全是1,因为0没用。。。)
D=AT×C
我们可以用
O(nd)
的时间求出来,
A×D
也可以用
O(nd)
的时间求出来,
B′×C
可以
O(n)
求出。
然后比较
A×(AT×C) B′×C
这两个列向量的每一个元素是否相同,如果第i行的元素不相同,说明
xi
肯定是答案只要,枚举找出
xj
即可。
尽管有出错的概率,但是这个算法还是比较可靠的。
k=3
我们发现
所以,我们令 B=(A∗AT)2 其余矩阵定义不变,那么展开后会发现
然后参考 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();
}