[BZOJ]3243 向量内积(Noi2013)
小C做了之后很有感觉的题目之一,但因为姿势不对调了很久。
Description
两个d 维向量A=[a1,a2,...,ad]与B=[b1,b2,...,bd]的内积为其相对应维度的权值的乘积和,即:
.jpg)
现有 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
N<=100000,D<=30,K<=3,Xi,j<10。

Solution
看见题目后基本能想到的要点:
①k似乎很小?k=2时答案只可能是0或1,k=3则是0、1和2?
②向量内积的求和式其实就是矩阵乘法的计算式,两个向量的内积可以看做是1*d和d*1的矩阵相乘。
继续深入:
①可以将题目表示为n*d和d*n的矩阵相乘,得到的n*n的矩阵就是n个向量两两之间的内积,判断n*n矩阵内是否有等于0的元素即可;
②直接计算和判断明显复杂度爆表,我们考虑将计算和判断部分进行优化:
当k=2时,n*n的矩阵只有一种情况不是我们想要的,那就是除了对角线上的元素,其他都为1——设这样的矩阵为D;
设原来的两个矩阵分别为A、B,相乘得到矩阵C;
这样我们只需判断C和D是否相等即可,我们当然不会直接判断,这里需要用到一个小技巧。
我们考虑随机生成一个n*1的矩阵T来与C、D相乘,判断C*T和D*T是否相等即可。
随机次数3~5次基本不会出错,这样我们便将判断成功降到了O(n)。
至于计算部分,我们只要按A*(B*T)的顺序就可以O(nd)得到C*T;
由于矩阵D是确定的,主对角线O(nd)计算,O(n)再推一遍可以得到D*T。
剩下的事情就是找出不相等的一位x,相当于找到了答案的一半(x一定是答案),O(nd)找另一半即可。
当k=3时,我们可以脑补一个2^2≡1(mod 3),于是考虑将矩阵C、D的每个元素平方(注意不是将矩阵平方!)。
这样矩阵D的每个除了主对角线上的元素便都是1了,像k=2那样判断C和D是否相等即可。
至于怎么计算矩阵C呢?我们发现

所以可以将矩阵A和B分别扩展成n*(d^2)和(d^2)*n的矩阵;
即将d维向量扩展成一个d^2维的向量,新向量每一维都是旧向量某两维的乘积。
有了这些,步骤基本就和k=2时的情况一样了。
时间复杂度:O(nd^2)
你会发现一个细节,数据中有n=10000,d=100,k=3的情况,n*(d^2)的空间完全不够开。
当然没有叫你真的开一个n*(d^2)的矩阵啊(坏笑)!你会发现涉及到矩阵乘法的操作只有在计算C*T的时候,也就是说只有4次,只要把k=3的那两次特殊抠出来处理即可,具体实现可以看小C的代码。
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#define MN 100005
#define MM 105
using namespace std;
struct matrix{int **ar; int h,l;}a,b,r,h;
int g[MN],f[MM],mod,n,m,sum; inline int read()
{
int n=,f=;char c=getchar();
while (c<'' || c>'') {if(c=='-')f=-; c=getchar();}
while (c>='' && c<='') {n=n*+c-''; c=getchar();}
return n*f;
} matrix newmatr(int n,int m)
{
matrix a;
a.h=n; a.l=m;
a.ar=new int*[n];
for (register int i=;i<n;++i) a.ar[i]=new int[m];
return a;
} matrix operator*(const matrix& a,const matrix& b)
{
matrix c=newmatr(a.h,b.l);
register int i,j,k;
for (i=;i<c.h;++i)
for (j=;j<c.l;c.ar[i][j++]%=mod)
for (c.ar[i][j]=,k=;k<a.l;++k) c.ar[i][j]+=a.ar[i][k]*b.ar[k][j];
return c;
} matrix operator&(const matrix& a,const matrix& b)
{
matrix c=newmatr(a.h,b.l);
register int i,j,kl,kr;
for (i=;i<c.h;++i)
for (j=;j<c.l;c.ar[i][j++]%=mod)
for (c.ar[i][j]=,kl=;kl<a.l;++kl)
for (kr=;kr<a.l;++kr) c.ar[i][j]+=a.ar[i][kl]*a.ar[i][kr]*b.ar[kl*a.l+kr][j];
return c;
} matrix operator|(const matrix& a,const matrix& b)
{
matrix c=newmatr(a.h*a.h,b.l);
register int i,j,k;
for (i=;i<c.h;++i)
{
register int x=i/a.h,y=i%a.h;
for (j=;j<c.l;c.ar[i][j++]%=mod)
for (c.ar[i][j]=,k=;k<a.l;++k) c.ar[i][j]+=a.ar[x][k]*a.ar[y][k]*b.ar[k][j];
}
return c;
} matrix ranmat(int n,int m)
{
matrix a=newmatr(n,m);
register int i,j;
for (i=;i<n;++i)
for (j=;j<m;++j) a.ar[i][j]=rand()%mod;
return a;
} int main()
{
srand();
register int i,j,k,o;
n=read(); m=read(); mod=read();
a=newmatr(n,m); b=newmatr(m,n);
for (i=;i<n;++i)
for (j=;j<m;++j) a.ar[i][j]=b.ar[j][i]=read()%mod;
for (i=;i<n;g[i++]%=mod)
for (j=;j<m;++j) g[i]+=a.ar[i][j]*a.ar[i][j];
if (mod==)
{
for (o=;o<=;++o)
{
r=ranmat(n,);
h=a*(b*r);
for (i=sum=;i<n;++i) sum^=r.ar[i][];
for (i=;i<n;++i) if (h.ar[i][]!=(sum^(r.ar[i][]&&!g[i]))) break;
if (i<n) break;
}
}
else if (mod==)
{
for (i=;i<n;++i) g[i]=g[i]*g[i]%mod;
for (o=;o<=;++o)
{
r=ranmat(n,);
h=a&(b|r);
for (i=sum=;i<n;++i) sum+=r.ar[i][];
for (i=;i<n;++i) if (h.ar[i][]!=(sum-(-g[i])*r.ar[i][])%mod) break;
if (i<n) break;
}
}
if (o>) return *printf("-1 -1");
for (j=;j<n;++j)
{
if (i==j) continue;
for (sum=k=;k<m;++k) sum+=a.ar[i][k]*a.ar[j][k];
if (!(sum%mod)) return *printf("%d %d",min(i+,j+),max(i+,j+));
}
}
Last Word
反正依着小C这属性(才不是抖M),能让他发博客吐槽的题目大概又是什么虐了他千百遍的丧题吧。(其实是因为小C智障老是打挂题)
一开始非常智障地跑去建n*(d^2)的矩阵,然后,然后就有了以上一段画风崩坏的代码……
由于用了结构体矩阵来计算,代码似乎跑得出奇地慢,洛谷和BZOJ上都过了,自家的OJ(未开O2)死活过不去……
所以不建议读者按矩阵计算,直接开数组即可,还有n*1的矩阵只要开成一维矩阵即可,这样代码效率可以有巨大的提升。
小C的代码效率较慢的锅都是因为开了二维数组,似乎 new 和 return结构体 在这道题效率还行?
总之,小C觉得这还算是一道挺有想法的题啦。其主要思想就是利用矩阵乘法的结合律来改变计算顺序以降低时间复杂度,还有就是在判断两个矩阵是否相等时用了一些小技巧,至于2^2≡1(mod 3)什么的就是脑洞问题了吧!(QAQ觉得脑洞平了)
[BZOJ]3243 向量内积(Noi2013)的更多相关文章
- BZOJ 3243 向量内积
Description 两个\(d\)维向量\(A=[a_{1},a_{2},...,a_{d}]\)与\(B=[b_{1},b_{2},...,b_{d}]\)的内积为其相对应维度的权值的乘积和,即 ...
- 【BZOJ3243】【NOI2013】向量内积(矩阵,数论)
[BZOJ3243][NOI2013]向量内积(矩阵,数论) 题面 BZOJ 题解 这题好神仙. 首先\(60\)分直接是送的.加点随机之类的可以多得点分. 考虑正解. 我们先考虑一下暴力. 我们把\ ...
- [Noi2013]向量内积
来自FallDream的博客,未经允许,请勿转载,谢谢. 两个d 维向量A=[a1,a2,...,ad]与B=[b1,b2,...,bd]的内积为其相对应维度的权值的乘积和,即: $\sum_{i=1 ...
- LOJ 2664. 「NOI2013」向量内积 解题报告
#2664. 「NOI2013」向量内积 两个 \(d\) 维向量 \(A=[a_1, a_2 ,...,a_d]\) 与 \(B=[b_1 ,b_2 ,...,b_d]\) 的内积为其相对应维度的权 ...
- 【fake题解】[NOI2013]向量内积
[fake题解][NOI2013]向量内积 做法1 大暴力.哪里不会T哪里. 做法2 所有数都%=k不影响结果.(废话 k的取值只有2和3,所以肯定是要分类讨论的.k=2肯定简单些啦. k=2 出现的 ...
- P1224 [NOI2013]向量内积
传送门 发现这个内积和矩乘有点像,考虑构造一个 $n$ 行 $m$ 列的矩阵 $A$,每一行都是一个题目给定的 $m$ 维向量 设 $B=AA^T$ ,其中 $A^T$ 为 $A$ 的转置矩阵,那么对 ...
- luogu P1224 [NOI2013]向量内积
传送门 挺有意思的一道题 暴力60就是枚举每个向量暴力check,随机选向量就能多骗一些分 然后两个向量内积要模\(k\)为\(0\),那么如果全部不为\(0\)就不合法.先考虑\(k=2\),对于向 ...
- 【BZOJ-3243】向量内积 随机化 + 矩阵
3243: [Noi2013]向量内积 Time Limit: 10 Sec Memory Limit: 256 MBSec Special JudgeSubmit: 1249 Solved: ...
- 3243: [Noi2013]向量内积 - BZOJ
Description 两个d 维向量A=[a1,a2,...,ad]与B=[b1,b2,...,bd]的内积为其相对应维度的权值的乘积和,即: 现有 n 个d 维向量x1,...,xn ,小喵喵想知 ...
随机推荐
- 织梦cms/dedecms清理冗余废弃未引用图片方法
原理描述: 在原有织梦后台菜单中增加"清理冗余图片按钮",实现清理冗余图片的功能. 操作步骤: 1. 打开后台dede\sys_sql_query.php代码 在该文件中搜索如下代 ...
- EasyUI中DataGrid隔行改变背景颜色。
<table id="dg" class="easyui-datagrid" style="width: 1000px; height: 300 ...
- php的api及登录的权限验证
类,库,接口(APi),函数,这些概念都是根据问题规模的大小来界定的.一个很小的问题肯定没有必要写成一个库,只需要写几句话就行了. 但是比如一个登录验证,这个功能很强大,很通用,可能前台后台都需要用到 ...
- java的<<左移,>>右移,>>>无符号右移
>>右移 右移,道在二进制中,假设用一个32位的Int表示一个64,那么高位就都是0,所以当我们把整个二进制数右移,如0100000 >> 2 = 0001000,可以看到右移 ...
- Struts2 配置文件小结
每次写的博文都被管理员都被移出首页,好气!还希望有哪位大神可以指点迷津-- struts2 配置文件的 result 节点 result 节点是 action 节点的子节点,他代表着 action 方 ...
- android 加速度传感器 ---摇一摇
package com.eboy.testyaoyiyao;import java.text.SimpleDateFormat;import java.util.Date;import android ...
- jacascript 鼠标事件和键盘事件
前言:这是笔者学习之后自己的理解与整理.如果有错误或者疑问的地方,请大家指正,我会持续更新! 鼠标事件 鼠标事件共10类,包括click.contextmenu(右键).dblclick(双击).mo ...
- springboot集成jpa
spring data jpa简介 spring data jpa是spring基于hibernate及jpa规范封装出来的一套持久层框架.该框架极大的降低了开发者工作量,提升开发效率.提供的关键字可 ...
- [C#].Net Core 获取 HttpContext.Current 以及 AsyncLocal 与 ThreadLocal
在 DotNetCore 当中不再像 MVC5 那样可以通过 HttpContext.Current 来获取到当前请求的上下文. 不过微软提供了一个 IHttpContextAccessor 来让我们 ...
- 是否可能两个ETH私钥对应同一个地址
原提问在这里. 笔者在使用到neon-js中的私钥生成方法时发现其使用了getRandomValues方法来生成64字符长度的私钥,进而考虑到其随机性,若是调用足够多次,依然有可能生成两个完全一样的私 ...