【BZOJ-3243】向量内积 随机化 + 矩阵
3243: [Noi2013]向量内积
Time Limit: 10 Sec Memory Limit: 256 MBSec Special JudgeSubmit: 1249 Solved: 248
[Submit][Status][Discuss]
Description
两个d 维向量A=[a1,a2,...,ad]与B=[b1,b2,...,bd]的内积为其相对应维度的权值的乘积和,即:
现有 n 个d 维向量x1,...,xn ,小喵喵想知道是否存在两个向量的内积为k的倍数。请帮助她解决这个问题
Input
Output
Sample Input
0 0 1 1 1 1 1 0 1 1 1 0 1 0 0 0 1 1 1 1
1 0 1 0 1 0 1 1 1 1 0 1 1 1 0 1 1 0 1 0
Sample Output
HINT
新增数据一组,但未重测By TA1111,2016.5.17
Source
Solution
这道题非常劲。
首先在这道题因为只是输出一组即可,所以,可以想到乱搞。
最暴力的方法就是$O(N^2d)$的复杂度枚举,非常不科学。
考虑利用矩阵的性质,直接用$A*A^{T}$,这样的复杂度还是$O(N^{2}d)$的。
然后我们考虑随机乱搞。 直接随机两个相乘,误差太大,复杂度极不稳定。
然后我们考虑拿一个向量,去和其他所有向量相乘。这样单次的复杂度是$O(Nd)$的,可以稍多做几次。
在$K=2$的时候,我们关心的是矩阵中是否有0,然后我们取这样一个向量做的时候,如果有一个位置不一样,那么就说明有不同。
然后我们就可以直接暴力的找这个不同的位置了。
这样也是有概率出错的,所以我们需要多做几次。
至于这个向量的选取,我们考虑随机一个向量。 对于这个矩阵,我们也可以随机一个排列,这样能降低错误概率。
然后就是$K=3$的情况了。 这样就不是直接考虑$modK$后1,0的情况了,因为这样会出现0,1,2的情况,然后很神奇的,$1^{2}=1mod3=1,2^{2}=4mod3=1$
然后我们对他们平方,就变成了$d^{2}$维的向量了,就又转变为上述情况了,复杂度自然也变成了$O(d^{2})$。
TA爷说这是卡不掉的。
需要随机的那个向量,是必须随机,因为如果构造的话,是可以卡的,比如构造全1向量就可以被卡。
讲道理应该多random_shuffle几遍的,但是我就random_suffle了一遍就很exciting的AC了...然而跑的还是不快。
Code
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cstdlib> #include<ctime> using namespace std; 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*10+ch-'0'; ch=getchar();} return x*f; } #define MAXN 100010 int N,d,K,A[MAXN][110],B[110],C[110][110]; int Judge(int x,int y) { int re=0; for (int i=1; i<=d; i++) re+=A[x][i]*A[y][i]; return re%K; } int OK(int x) { int re=0; if (K==2) for (int i=1; i<=d; i++) re^=B[i]&A[x][i],B[i]^=A[x][i]; else for (int i=1; i<=d; i++) for (int j=1; j<=d; j++) re+=C[i][j]*A[x][i]*A[x][j],(C[i][j]+=A[x][i]*A[x][j])%=K; return re%K; } int id[MAXN]; void Solve() { for (int i=1; i<=N; i++) id[i]=i; random_shuffle(id+1,id+N+1); memset(B,0,sizeof(B)); memset(C,0,sizeof(C)); for (int i=1; i<=N; i++) if (OK(id[i])!=(i-1)%K) for (int x,y,j=1; j<=i-1; j++) if (!Judge(id[i],id[j])) x=min(id[i],id[j]),y=max(id[i],id[j]),printf("%d %d\n",x,y),exit(0); } int main() { N=read(); d=read(); K=read(); for (int i=1; i<=N; i++) for (int j=1; j<=d; j++) A[i][j]=read()%K; for (int i=1; i<=1; i++) Solve(); puts("-1 -1"); return 0; }