zoukankan      html  css  js  c++  java
  • 【NOI2013】向量内积

    题面

    https://www.luogu.org/problem/P1224

    题解

    窝本来想用这道题写矩阵哈希的,所谓矩阵哈希,就是快速判断两个矩阵的乘积是不是另外一个矩阵。

    矩阵哈希就是随机一个向量,利用矩阵结合律先算向量和各矩阵的乘积,然后直接比较两个向量是不是相等的。

    这样本来是$n^3$的,就变成$n^2$的。

    但是看到题解第一种方法更简便而且更易懂,就写第一种方法了。

    所谓内积,就是点乘。

    首先是二维的情况,假设检查到$i$个,我们检查$i$和$1..i-1$的前缀和的内积是否为$(i-1)\% 2$,如果不是,一定说明$i$和前面的某个$x$的内积是2的倍数,遍历$1~i-1$检查一遍。否则,不知道有没有,就不检查了。

    三维的情况不能直接套用,因为如果内积不是$3$的倍数,不知道具体是余$1$还是余$2$,但是我们知道,不管是$1$还是$2$,他们的平方都是余$1$的(记得当年在奥数班,南小大聚聚$xjt$讲的结论),所以我们考虑求的形式$$(a_1b_1+a_2b_2+...+a_kb_k)^2=a_1b_1 imes(a_1b_1+....+a_kb_k)+....+a_kb_k imes(a_1b_1+....+a_kb_k)$$,所以拆成$k^2$维的向量(或者说,拆成$k imes k$的“矩阵”)

    然后很寒掺,只有$85$分,最后$3$个点$T$了,我也不知道怎么回事啊。

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #define ri register int
    #define N 100050
    #define D 105
    using namespace std;
    int n,d,k;
    int v[N][D];
    int b[D],c[D][D];
    int id[N];
    
    inline int read() {
      register char ch=getchar(); ri ret=0;
      while (ch<'0'||ch>'9') ch=getchar();
      while (ch>='0' && ch<='9') ret=ret*10+(ch-'0'),ch=getchar();
      return ret;
    }
    
    inline int work(int cur) {
      ri ret=0;
      if (k==2) {
        for (ri i=1;i<=d;i++) ret+=b[i]*v[id[cur]][i];
        for (ri i=1;i<=d;i++) b[i]+=v[id[cur]][i],b[i]%=2;
      }
      else {
        for (ri i=1;i<=d;i++)
          for (ri j=1;j<=d;j++) ret+=c[i][j]*v[id[cur]][i]*v[id[cur]][j];
        for (ri i=1;i<=d;i++)
          for (ri j=1;j<=d;j++) c[i][j]+=v[id[cur]][i]*v[id[cur]][j],c[i][j]%=3;
      }
      return ret%k;
    }
    
    inline bool check(int cur) {
      for (ri i=1;i<cur;i++) {
        ri ret=0;
        for (ri j=1;j<=d;j++) ret+=v[id[cur]][j]*v[id[i]][j];
        if (ret%k==0) {
          int x=id[i],y=id[cur];
          if (x>y) swap(x,y);
          printf("%d %d
    ",x,y);
          return 1;
        }
      }
      return 0;
    }
    
    int main(){
      //scanf("%d %d %d",&n,&d,&k);
      n=read(); d=read(); k=read();
      for (ri i=1;i<=n;i++) 
        for (ri j=1;j<=d;j++) v[i][j]=read()%k;
      for (ri i=1;i<=n;i++) id[i]=i;
      int ks=5;
      while (ks--) {
        memset(b,0,sizeof(b));
        memset(c,0,sizeof(c));
        random_shuffle(id+1,id+n+1);
        for (ri i=1;i<=n;i++) {
          int t=work(i);
          if (t!=(i-1)%2) if (check(i)) return 0;
        }
      }
      puts("-1 -1");
      return 0;
    }
  • 相关阅读:
    Shell重新学习(忘光了)
    vim 设置默认显示行号
    maven学习资料(三)
    maven:新建的maven工程需要添加一下插件
    Spring框架:第五章:Spring EL表达式
    Spring框架:第四章:Spring管理数据库连接池
    Spring框架:第三章:对象的生命周期及单例bean生命周期的11个步骤
    Spring框架:第二章:IOC依赖注入及40个实验
    Spring框架:第一章:介绍和准备工作
    MyBatis框架:第十一章:mybatis 逆向工程
  • 原文地址:https://www.cnblogs.com/shxnb666/p/11426210.html
Copyright © 2011-2022 走看看