• [Noi2013]向量内积


    来自FallDream的博客,未经允许,请勿转载,谢谢。


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

    $sum_{i=1}^{d}ai*bi$

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

    k=2时 n<=20000 d<=100  k=3时n<=1000,d<=100 或者n<=100000 d<=30

    把两个向量内积看作矩阵一个1*d的矩阵和d*1的矩阵相乘

    那么k=2的时候,就是一个n*d的矩阵和一个d*n的矩阵相乘,问得到的n*n的矩阵除了主对角线之外有没有0(mod k)

    直接计算复杂度n^2d 所以不考虑计算它,而是转而判断得到的矩阵是否等于我想要的矩阵

    假设n*d的矩阵为A,把它倒过来之后得到的d*n的矩阵为B,C=A*B,我期望的矩阵为D

    矩阵D的主对角线的值可以O(nd)计算,其他值显然是1。

    要判断C是否等于D,我可以转而随机一个n*1的向量T,判断C*T是否等于D*T即可

    因为T只存在0和1,所以D*T可快速计算 而计算A*B*T时,我们可以先计算B*T,再计算A*(B*T),这两次计算都是O(nd)的

    那么就做完了。复杂度O(nd)

    但是k=3的时候,无法直接知道期望的矩阵,但是发现2^2=1(mod 3)

    于是考虑计算E,Eij=Cij^2;矩阵D主对角线也对应平方一下 

    发现$Eij=(sum Aik*Bkj)^{2}$ 展开后得到$Eij=sum_{k1=1}^{d}sum_{k2=1}^{d}Aik1*Bk1j*Aik2*Bk2j$

    这个可以看作$n*d^{2}$的矩阵和一个$d^{2}*n$的矩阵相乘 之后就按照k=2的做法就行了 复杂度$O(nd^{2})$

    但是这个办法并不能保证正确 如果直接让矩阵T都是1的话 在bzoj会被叉...

    所以我们多随机几次就行了 一般都能过的吧

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define rint register int
    #define getchar() (*S++)
    char BB[1<<26],*S=BB;
    using namespace std;
    inline 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;
    }
    
    int A[100005][105],B[100005],C[100005],D[100005],E[100005],n,d,K,cnt=0,sum=0,id[105][105];
    
    inline bool check(int a,int b)
    {
        int Sum=0;
        for(rint i=1;i<=d;++i)
            Sum+=A[a][i]*A[b][i];
        return Sum%K==0;
    }
    
    inline void Solve(int x)
    {
        for(rint i=1;i<=n;++i)
            if(i!=x&&check(i,x))
                {printf("%d %d
    ",min(x,i),max(x,i));return;}
    }
    
    int main()
    {
        fread(BB,1,1<<26,stdin);
        srand(23333U);
        n=read();d=read();K=read();
        for(rint i=1;i<=n;++i)
            for(rint j=1;j<=d;++j)
                A[i][j]=read()%K;
        if(K==2) for(int It=1;It<=5;++It)
        {
            for(rint i=1;i<=n;++i) C[i]=rand()&1,sum+=C[i];
            for(rint i=1;i<=n;++i)
                for(rint j=1;j<=d;++j)
                    B[j]+=A[i][j]*C[i];
            for(rint i=1;i<=d;++i) B[i]%=K;
            for(rint i=1;i<=n;++i)
                for(rint j=1;j<=d;++j)
                    D[i]+=A[i][j]*B[j];
            for(rint i=1;i<=n;++i)
                for(rint j=1;j<=d;++j)
                    E[i]+=A[i][j];
            for(rint i=1;i<=n;++i) E[i]=(E[i]*C[i]+sum-C[i])%K;
            for(rint i=1;i<=n;++i) if(E[i]!=(D[i]%K)) return Solve(i),0;
            sum=0;
            for(rint i=1;i<=n;++i) E[i]=D[i]=B[i]=0;
        }
        else for(int It=1;It<=5;++It)
        {
            for(rint i=1;i<=n;++i) C[i]=rand()%3,sum+=C[i];
            for(rint i=1;i<=d;++i)
                for(rint j=1;j<=d;++j)
                    id[i][j]=++cnt;
            for(rint k=1;k<=n;++k)
                for(rint i=1;i<=d;++i)
                    for(rint j=1;j<=d;++j)
                        B[id[i][j]]+=A[k][i]*A[k][j]*C[k];
            for(rint i=1;i<=cnt;i++) B[i]%=K;
            for(rint i=1;i<=n;++i)
                for(rint j=1;j<=d;++j)
                    for(rint k=1;k<=d;++k)
                        D[i]+=A[i][j]*A[i][k]*B[id[j][k]];
            for(rint i=1;i<=n;++i)
                for(rint j=1;j<=d;++j)
                    E[i]+=A[i][j]*A[i][j];
            for(rint i=1;i<=n;++i) E[i]%=K,E[i]=(E[i]*E[i]*C[i]+sum-C[i])%K;
            for(rint i=1;i<=n;++i) if(E[i]!=(D[i]%K)) return Solve(i),0;
            sum=0;
            for(rint i=1;i<=n;++i) E[i]=D[i]=B[i]=0;
        }
        return 0*puts("-1 -1");
    }
  • 相关阅读:
    angular手势事件之on-Hold
    angular 控制器的使用两种模式
    关于IONIC 报错 XX is not a function
    ionic 中$ionicView.beforeEnter 事件的一个bug
    开发一个IONIC应用的首要操作(宏观)
    在线常用库 + API手册
    关于日历实现代码里lunarInfo(农历)数组
    YSlow
    GET and POST
    Yahoo34条军规——雅虎WEB前端网站优化
  • 原文地址:https://www.cnblogs.com/FallDream/p/noi2013d1t1.html
Copyright © 2020-2023  润新知