【数学一本通 第六章】向量內积 [LUOGU P1224] [NOI 2013]

题目:

题目链接:向量内积
题解:
在源神的大力相助以及题解的帮助之下,我这个菜鸡终于懂了,太不容易了,想思路想了将近两个小时,太菜了(〃>_<;〃)
还是想先手推一下样例:
1 0 1 0 1
1 1 0 1 0
0 1 0 1 1
则內积就为:1×0 + 1×1 + 0×0 + 1×1 + 0×1=2 % 2=0
所以,我们就需要从所有行中找到某二或三行中找到內积%k=0即可。

这样的话,由题意可知,A·AT是一个01矩阵,我们就设一个全1的矩阵C,则A·AT=C,我们再设一个1×n的矩阵(一行矩阵)S,则,S×(A·AT)=S×C,这样的话,我们就可以很容易的算出来S×C,再对S×(A·AT)进行展开优化即可。

但是,当k=3时该怎么办呢?
当k=3,的时候,这就不在是一个01矩阵了,这就是一个012的矩阵了,但是我们只需要记录下来0的可能就行,所以这该怎么办呢?

可以考虑一下, 2 x ≡ 1 ( m o d 3 ) 2^x≡1(mod 3) 2x1(mod3),那么x就肯定是2了,所以,我们就可以把情况转化为:将A,AT两者相乘之后再平方一下再%3,这样的话就可以完全避免掉012的矩阵,从而将012矩阵转化为01矩阵。这样就转化成了上面的形式。

说一下平方后的通项公式:
A × A T = S 1 = ∑ k = 1 d a i k ⋅ a j k A×A^T=S_1=\sum_{k=1}^da_{ik}·a_{jk} A×AT=S1=k=1daikajk
S 1 2 = ∑ k 1 = 1 d ∑ k 2 = 1 d a i k 1 ⋅ a j k 1 ⋅ a i k 2 ⋅ a j k 2 S_1^2=\sum_{k_1=1}^d\sum_{k_2=1}^da_{ik_1}·a_{jk_1}·a_{ik_2}·a_{jk_2} S12=k1=1dk2=1daik1ajk1aik2ajk2
这样就好了。

代码:

#include<bits/stdc++.h>
using namespace std;
const int sea=100020;
int a[sea][110],n,m,k;
int S1[sea],S2[sea][110],id[sea];
inline int read()
{
	int s=0,w=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')w=-1; ch=getchar();}
	while(ch<='9'&&ch>='0')s=s*10+ch-'0',ch=getchar();
	return s*w;
}
int judge(int x,int y)//匹配 
{
	int s=0;
	for(int i=1;i<=m;i++) s+=a[x][i]*a[y][i];
	return (s%k==0);
}
int work(int x)
{
	int ans=0;
	if(k==2) //O(d)的匹配 
	for(int i=1;i<=m;S1[i]^=a[x][i],i++) ans^=(S1[i]&a[x][i]);
	else //O(d^2)的匹配 
		for(int i=1;i<=m;i++)
		for(int j=1;j<=m;S2[i][j]+=a[x][i]*a[x][j],j++)
		ans+=S2[i][j]*a[x][i]*a[x][j];//自己求通项 
	return ans%k;
}
int main()
{
	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;
	for(int i=1;i<=n;i++) id[i]=i;
	int T=7;
	while(T--)
	{
		memset(S1,0,sizeof(S1));  memset(S2,0,sizeof(S2)); 
		random_shuffle(id+1,id+n+1);//随机数
		for(int i=1;i<=n;i++)  if(work(id[i])!=(i-1)%k)
		for(int j=1;j<i;j++)
		if(judge(id[i],id[j]))
		{
			if(id[i]>id[j]) swap(i,j);
			printf("%d %d\n",id[i],id[j]);
			return 0; 
		}
	}
	puts("-1 -1");
	return 0;
}

continue……

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值