来自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[<<],*S=BB;
using namespace std;
inline int read()
{
int x = ; char ch = getchar();
while(ch < '' || ch > '') ch = getchar();
while(ch >= '' && ch <= ''){x = x * + ch - '';ch = getchar();}
return x;
} int A[][],B[],C[],D[],E[],n,d,K,cnt=,sum=,id[][]; inline bool check(int a,int b)
{
int Sum=;
for(rint i=;i<=d;++i)
Sum+=A[a][i]*A[b][i];
return Sum%K==;
} inline void Solve(int x)
{
for(rint i=;i<=n;++i)
if(i!=x&&check(i,x))
{printf("%d %d\n",min(x,i),max(x,i));return;}
} int main()
{
fread(BB,,<<,stdin);
srand(23333U);
n=read();d=read();K=read();
for(rint i=;i<=n;++i)
for(rint j=;j<=d;++j)
A[i][j]=read()%K;
if(K==) for(int It=;It<=;++It)
{
for(rint i=;i<=n;++i) C[i]=rand()&,sum+=C[i];
for(rint i=;i<=n;++i)
for(rint j=;j<=d;++j)
B[j]+=A[i][j]*C[i];
for(rint i=;i<=d;++i) B[i]%=K;
for(rint i=;i<=n;++i)
for(rint j=;j<=d;++j)
D[i]+=A[i][j]*B[j];
for(rint i=;i<=n;++i)
for(rint j=;j<=d;++j)
E[i]+=A[i][j];
for(rint i=;i<=n;++i) E[i]=(E[i]*C[i]+sum-C[i])%K;
for(rint i=;i<=n;++i) if(E[i]!=(D[i]%K)) return Solve(i),;
sum=;
for(rint i=;i<=n;++i) E[i]=D[i]=B[i]=;
}
else for(int It=;It<=;++It)
{
for(rint i=;i<=n;++i) C[i]=rand()%,sum+=C[i];
for(rint i=;i<=d;++i)
for(rint j=;j<=d;++j)
id[i][j]=++cnt;
for(rint k=;k<=n;++k)
for(rint i=;i<=d;++i)
for(rint j=;j<=d;++j)
B[id[i][j]]+=A[k][i]*A[k][j]*C[k];
for(rint i=;i<=cnt;i++) B[i]%=K;
for(rint i=;i<=n;++i)
for(rint j=;j<=d;++j)
for(rint k=;k<=d;++k)
D[i]+=A[i][j]*A[i][k]*B[id[j][k]];
for(rint i=;i<=n;++i)
for(rint j=;j<=d;++j)
E[i]+=A[i][j]*A[i][j];
for(rint i=;i<=n;++i) E[i]%=K,E[i]=(E[i]*E[i]*C[i]+sum-C[i])%K;
for(rint i=;i<=n;++i) if(E[i]!=(D[i]%K)) return Solve(i),;
sum=;
for(rint i=;i<=n;++i) E[i]=D[i]=B[i]=;
}
return *puts("-1 -1");
}

[Noi2013]向量内积的更多相关文章

  1. 【fake题解】[NOI2013]向量内积

    [fake题解][NOI2013]向量内积 做法1 大暴力.哪里不会T哪里. 做法2 所有数都%=k不影响结果.(废话 k的取值只有2和3,所以肯定是要分类讨论的.k=2肯定简单些啦. k=2 出现的 ...

  2. P1224 [NOI2013]向量内积

    传送门 发现这个内积和矩乘有点像,考虑构造一个 $n$ 行 $m$ 列的矩阵 $A$,每一行都是一个题目给定的 $m$ 维向量 设 $B=AA^T$ ,其中 $A^T$ 为 $A$ 的转置矩阵,那么对 ...

  3. luogu P1224 [NOI2013]向量内积

    传送门 挺有意思的一道题 暴力60就是枚举每个向量暴力check,随机选向量就能多骗一些分 然后两个向量内积要模\(k\)为\(0\),那么如果全部不为\(0\)就不合法.先考虑\(k=2\),对于向 ...

  4. 3243: [Noi2013]向量内积 - BZOJ

    Description 两个d 维向量A=[a1,a2,...,ad]与B=[b1,b2,...,bd]的内积为其相对应维度的权值的乘积和,即: 现有 n 个d 维向量x1,...,xn ,小喵喵想知 ...

  5. 【uoj121】 NOI2013—向量内积

    http://uoj.ac/problem/121 (题目链接) 题意 给出${n}$个${d}$维向量,问是否有两个不同的向量的内积是${k}$的倍数. Solution 又卡了一上午常数,我弃了T ...

  6. bzoj 3243: [Noi2013]向量内积

    Description 两个d 维向量A=[a1,a2,...,ad]与B=[b1,b2,...,bd]的内积为其相对应维度的权值的乘积和,即: 现有 n 个d 维向量x1,...,xn ,小喵喵想知 ...

  7. BZOJ3243/UOJ121 [Noi2013]向量内积

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  8. BZOJ3243 NOI2013向量内积(随机化)

    考虑奇技淫巧. 首先是k=2.对向量维护一个前缀和,每次将当前向量与前缀和点乘.如果点乘结果不等于i-1&1,说明当前向量至少和之前的某个向量的数量积是2的倍数,暴力找就可以了.当然等于i-1 ...

  9. BZOJ3243 [Noi2013]向量内积 【乱搞】

    题目链接 BZOJ3243 题解 模数只有\(2\)或\(3\),可以大力讨论 如果模数为\(2\),乘积结果只有\(1\)或\(0\) 如果一个向量和前面所有向量乘积都为\(1\),那么其和前面向量 ...

随机推荐

  1. socket_sever实现多客户端并发

    #!/usr/bin/env python # -*- coding:utf-8 -*- import socketserver class mysever(socketserver.BaseRequ ...

  2. [译]RabbitMQ教程C#版 - 工作队列

    先决条件 本教程假定RabbitMQ已经安装,并运行在localhost标准端口(5672).如果你使用不同的主机.端口或证书,则需要调整连接设置. 从哪里获得帮助 如果您在阅读本教程时遇到困难,可以 ...

  3. System.Reflection名称空间下的程序集类Assembly应用.

    利用反射中的程序集类(Assembly--抽象类)动态加载类库(.dll)或者可执行程序(.exe). 优点:①.可以消除if条件的逻辑判断.②.减少内存资源.③.有利于程序扩展. 缺点... 使用静 ...

  4. H5 音频标签自定义样式修改以及添加播放控制事件

    说明: 需求要求这个音频标签首先要是可适配移动端浏览器的,音频样式就是参考微信做的. 最终效果如下: 具体实现 思路: H5 的 <audio> 标签是由浏览器负责实现默认样式的.所以不同 ...

  5. 微信小程序组件学习中

    一.轮播图 wxml代码: <swiper indicator-dots="true" autoplay="true" duration="10 ...

  6. emqtt 试用(九)ssl认证 - 客户端 mqttfx 验证

    一.代码生成证书 1.安装openssl,配置path变量 安装文件:Win64OpenSSL-1_1_0f.exe 安装openssl:C:\OpenSSL-Win64 配置path变量:C:\Op ...

  7. ssm框架找不到mysql驱动类WARN DriverManagerDataSource:107 - Could not load driverClass com.mysql.jdbc.Driver

    找了很久错误,检查了配置文件,和spring配置数据源,都没有发现问题,最后上网查询了下,发现是由于配置文件后面有空格. 去除掉配置文件后面的空格就可以正常运行了.

  8. Codeforces Round #441 (Div. 2, by Moscow Team Olympiad) B. Divisiblity of Differences

    http://codeforces.com/contest/876/problem/B 题意: 给出n个数,要求从里面选出k个数使得这k个数中任意两个的差能够被m整除,若不能则输出no. 思路: 差能 ...

  9. POJ-3026 Borg Maze---BFS预处理+最小生成树

    题目链接: https://vjudge.net/problem/POJ-3026 题目大意: 在一个y行 x列的迷宫中,有可行走的通路空格' ',不可行走的墙'#',还有两种英文字母A和S,现在从S ...

  10. canvas实现的粒子效果

    前言:我的这个share很简单,没什么技术水准,主要是我自己觉得canvas这个标签很cool!,简单实用又能装X,而且又能实现很多看起来很炫的东西. 一 关于canvas <canvas> ...