P1224 [NOI2013]向量内积
发现这个内积和矩乘有点像,考虑构造一个 $n$ 行 $m$ 列的矩阵 $A$,每一行都是一个题目给定的 $m$ 维向量
设 $B=AA^T$ ,其中 $A^T$ 为 $A$ 的转置矩阵,那么对于 $B_{i,j}$ 的值,它其实就是向量 $i$ 和向量 $j$ 的内积
注意到 $K$ 只有 $2$ 或 $3$,先考虑 $K=2$ 时的情况
此时就是问矩阵 $B$ 在模 $2$ 意义下是否有位置的值为 $0$ ,并且求出位置
首先判断是否有 $0$ ,因为此时 $B$ 的元素不是 $0$ 就是 $1$ ,所以就是比较 $B$ 和全 $1$ 矩阵 $C$ 是否相等
所以就是要快速判断 $AA^T=C$ ,至于快速判断矩阵乘积结果是否等于给定矩阵,是有套路的
设 $D$ 为 $1$ 行 $n$ 列的随机矩阵,那么如果 $DAA^T \neq DC$ 那么显然 $AA^T \neq C$,否则还有概率是因为 $D$ 的影响才相等,我们多做几次判断即可
这样矩乘的复杂度就会低很多,判断 $DAA^T$ 是否等于 $DC$ 时,如果 $DC$ 的第 $i$ 个位置和 $DAA^T$ 不相等,那么说明向量 $i$ 和某个向量内积不是 $K$ 的倍数,此时我们只要枚举另一个向量 $j$ 并暴力判断即可
对于 $K=3$ 的情况,发现 $B$ 的元素不只是 $0,1$ 还有 $2$ ,似乎没法判断了
但是注意到(我也不知道怎么注意到的) $2^2 \equiv 1 \mod 3,1^2 \equiv 1 \mod 3,0^2 \equiv 0 \mod 3$
所以如果我们能把 $B$ 的每个元素平方,那么 $B$ 就又变成了 $01$ 矩阵,直接枚举元素再平方显然会 $T$ 飞
所以写写式子, $B_{i,j}=A_i \cdot A_j=\sum_{k=1}^{m}A_{i,k} \cdot A_{j,k}$,$(B_{i,j})^2=(\sum_{k=1}^{m}A_{i,k} \cdot A_{j,k})(\sum_{k=1}^{m}A_{i,k} \cdot A_{j,k})$
$(B_{i,j})^2=\sum_{k_1=1}^{m}\sum_{k2=1}^{m}(A_{i,k_1}A_{i,k_2})(A_{j,k_1}A_{j,k_2})$
所以我们把向量变成 $m^2$ 维,$A'_{i,(k_1-1)*m+k_2}=A_{i,k_1} \cdot A_{i,k_2}$
然后就可以用同样的方法判断了,当然 $A'$ 不能直接生成,我们只能存一下 $x=(k_1-1)*m+k_2$ 时的 $k_1,k_2$ 乘的时候再利用 $A_{i,k_1},A_{i,k_2}$ 进行计算
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<cstdlib> using namespace std; typedef long long ll; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int N=1e5+7,M=107; int n,m,K; inline int fk(int x) { return x>=K ? x-K : x; } int A[N][M],B[N],C[N],D[N]; inline bool check(int i,int j) { int res=0; for(int k=1;k<=m;k++) res=fk(res+A[i][k]*A[j][k]%K); return res==0; } inline int find(int p) { for(int i=1;i<=n;i++) if(i!=p&&check(i,p)) return i; return 0; } void solve1() { for(int I=1;I<=10;I++) { int tot=0; for(int i=1;i<=n;i++) B[i]=rand()&1,tot+=B[i]; tot%=K; for(int i=1;i<=m;i++) C[i]=0; for(int i=1;i<=n;i++) D[i]=0; for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) C[i]+=B[j]*A[j][i]; for(int i=1;i<=m;i++) C[i]%=K; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) D[i]+=C[j]*A[i][j]; D[i]%=K; if(D[i]==tot) continue; int x=i,y=find(i); printf("%d %d\n",min(x,y),max(x,y)); return; } } printf("-1 -1\n"); } int l[N],r[N]; void solve2() { int mm=m*m; for(int i=1;i<=mm;i++) { int t=i/m+(i%m!=0); l[i]=t; r[i]=i-(t-1)*m; } for(int I=1;I<=10;I++) { int tot=0; for(int i=1;i<=n;i++) B[i]=rand()&1,tot+=B[i]; tot%=K; for(int i=1;i<=mm;i++) C[i]=0; for(int i=1;i<=n;i++) D[i]=0; for(int i=1;i<=mm;i++) for(int j=1;j<=n;j++) C[i]+=B[j]*A[j][l[i]]*A[j][r[i]]; for(int i=1;i<=n;i++) { for(int j=1;j<=mm;j++) D[i]+=C[j]*A[i][l[j]]*A[i][r[j]]; D[i]%=K; if(D[i]==tot) continue; int x=i,y=find(i); printf("%d %d\n",min(x,y),max(x,y)); return; } } printf("-1 -1\n"); } int main() { srand(998244353); n=read(),m=read(),K=read(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) A[i][j]=read()%K; if(K==2) solve1(); else solve2(); return 0; }
原文地址:https://www.cnblogs.com/LLTYYC/p/11538360.html
- 【深度学习】谷歌deepdream原理及tensorflow实现
- 【深度学习】写诗机器人tensorflow实现
- PyTorch还是TensorFlow?这有一份新手指南
- Leetcode 300. Longest Increasing Subsequence
- Leetcode 299. Bulls and Cows
- Leetcode 297. Serialize and Deserialize Binary Tree
- Leetcode 295. Find Median from Data Stream
- 投入大见效慢,还要做AI?
- Leetcode 292. Nim Game
- Leetcode 290. Word Pattern
- 【深度学习】使用tensorflow实现VGG19网络
- Leetcode 289. Game of Life
- Leetcode 287. Find the Duplicate Number
- Leetcode 284. Peeking Iterator
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法