• 【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;
    }
  • 相关阅读:
    [文摘20080731]小破孩的婚姻
    Response.Redirect和Server.Transfer(Execute)的区别小论集锦
    学习FotoVision 进行C# colorMatrix 对图片的处理 : 亮度调整 抓屏 翻转 随鼠标画矩形
    [转]通过分区(Partition)提升MySQL性能
    [书目20080829]软件测试技术经典教程
    [转]c# + mysql + 事务处理(转载于 《C#数据库事务原理及实践》)
    遭遇 VS 的 无法调试引用的类库项目(DLL)问题(生成下面的模块时,启用了优化或没有调试信息)
    [转]C#动态生成文字图片
    命令行 SC命令 及通过sc config 更该windows服务的启动类型等
    [转]flash 与 js 通讯方法
  • 原文地址:https://www.cnblogs.com/shxnb666/p/11426210.html
Copyright © 2020-2023  润新知