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;
    }
  • 相关阅读:
    ubuntu 源
    20121211 mysqld.sock丢失无法启动mysql和登陆
    hadoop0.20.2 & hbase0.90.1 集群启动错误“org.apache.hadoop.ipc.RPC$VersionMismatch: Protocol org.apache.hadoop.hdfs.protocol.ClientP
    20121204当前集群的几个问题
    hive中的bucket table (输入文件是一个的话,map任务只能启动一个 ,给力啊)
    Android的animation
    获取已安装程序的名字、包名
    android布局属性
    Ghost网络克隆详细步骤教程
    教你如何用PQ魔法师调整硬盘分区大小【图解教程】
  • 原文地址:https://www.cnblogs.com/shxnb666/p/11426210.html
Copyright © 2011-2022 走看看