• 【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
    ",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;
    }
  • 相关阅读:
    Python学习————并发编程
    Python学习————作业
    Python学习————网络编程
    Python学习————异常处理
    Python学习————反射
    Python学习————绑定方法
    Python学习————继承
    1765 谷歌的恐龙
    2504 是子序列的个数
    51Nod2386 分则能成
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5943502.html
Copyright © 2020-2023  润新知