【BZOJ-3243】向量内积 随机化 + 矩阵

3243: [Noi2013]向量内积

Time Limit: 10 Sec  Memory Limit: 256 MBSec  Special Judge
Submit: 1249  Solved: 248
[Submit][Status][Discuss]

Description

两个d 维向量A=[a1,a2,...,ad]与B=[b1,b2,...,bd]的内积为其相对应维度的权值的乘积和,即:

现有 n 个d 维向量x1,...,xn ,小喵喵想知道是否存在两个向量的内积为k的倍数。请帮助她解决这个问题

Input

第一行包含3个正整数n,d,k,分别表示向量的个数,维数以及待检测的倍数。接下来n行每行有d个非负整数,其中第i行的第j个整数表示向量xi的第j维权值xi,j。
N<=100000,D<=30,K<=3,Xi,j<10

Output

包含两个整数,用空格隔开。如果存在两个向量xp,xq的内积为k的整数倍,则输出两个向量的编号p与q(要求p<q)。如果存在多组这样的向量组合,输出其中任意一组即可。若不存在这样的向量组合,则输出两个-1。

Sample Input

2 20 2
0 0 1 1 1 1 1 0 1 1 1 0 1 0 0 0 1 1 1 1
1 0 1 0 1 0 1 1 1 1 0 1 1 1 0 1 1 0 1 0

Sample Output

1 2

HINT

新增数据一组,但未重测By TA1111,2016.5.17

Source

Solution

这道题非常劲。

首先在这道题因为只是输出一组即可,所以,可以想到乱搞。

最暴力的方法就是$O(N^2d)$的复杂度枚举,非常不科学。

考虑利用矩阵的性质,直接用$A*A^{T}$,这样的复杂度还是$O(N^{2}d)$的。

然后我们考虑随机乱搞。 直接随机两个相乘,误差太大,复杂度极不稳定。

然后我们考虑拿一个向量,去和其他所有向量相乘。这样单次的复杂度是$O(Nd)$的,可以稍多做几次。

在$K=2$的时候,我们关心的是矩阵中是否有0,然后我们取这样一个向量做的时候,如果有一个位置不一样,那么就说明有不同。

然后我们就可以直接暴力的找这个不同的位置了。

这样也是有概率出错的,所以我们需要多做几次。

至于这个向量的选取,我们考虑随机一个向量。 对于这个矩阵,我们也可以随机一个排列,这样能降低错误概率。

然后就是$K=3$的情况了。 这样就不是直接考虑$modK$后1,0的情况了,因为这样会出现0,1,2的情况,然后很神奇的,$1^{2}=1mod3=1,2^{2}=4mod3=1$

然后我们对他们平方,就变成了$d^{2}$维的向量了,就又转变为上述情况了,复杂度自然也变成了$O(d^{2})$。

TA爷说这是卡不掉的。

需要随机的那个向量,是必须随机,因为如果构造的话,是可以卡的,比如构造全1向量就可以被卡。

讲道理应该多random_shuffle几遍的,但是我就random_suffle了一遍就很exciting的AC了...然而跑的还是不快。

Code

#include<iostream>
#include<algorithm> 
#include<cstdio>
#include<cstring> 
#include<cstdlib> 
#include<ctime>
using namespace std;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
    while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
#define MAXN 100010
int N,d,K,A[MAXN][110],B[110],C[110][110];
int Judge(int x,int y)
{
    int re=0;
    for (int i=1; i<=d; i++) re+=A[x][i]*A[y][i];
    return re%K;
}
int OK(int x)
{
    int re=0;
    if (K==2)
        for (int i=1; i<=d; i++) re^=B[i]&A[x][i],B[i]^=A[x][i];
    else
        for (int i=1; i<=d; i++)
            for (int j=1; j<=d; j++)
                re+=C[i][j]*A[x][i]*A[x][j],(C[i][j]+=A[x][i]*A[x][j])%=K;
    return re%K;
}
int id[MAXN];
void Solve()
{
    for (int i=1; i<=N; i++) id[i]=i;
    random_shuffle(id+1,id+N+1);
    memset(B,0,sizeof(B)); memset(C,0,sizeof(C));
    for (int i=1; i<=N; i++) 
        if (OK(id[i])!=(i-1)%K)
            for (int x,y,j=1; j<=i-1; j++)
                if (!Judge(id[i],id[j]))
                    x=min(id[i],id[j]),y=max(id[i],id[j]),printf("%d %d\n",x,y),exit(0);
}
int main()
{
    N=read(); d=read(); K=read();
    for (int i=1; i<=N; i++)
        for (int j=1; j<=d; j++)
            A[i][j]=read()%K;
    for (int i=1; i<=1; i++) Solve();
    puts("-1 -1");
    return 0;
}

 

posted @ 2016-10-09 19:32  DaD3zZ  阅读(351)  评论(0编辑  收藏  举报