loading

P1224 [NOI2013] 向量内积

题意

给定 \(n\)\(d\) 维向量 \(a_i\),求一对合法的 \(i,j\) 使得 \(a_i\cdot a_j=0\),其中 \(\cdot\) 是向量点积,即 \(a_i\cdot a_j=\sum_{p=1}^d a_{i,p}a_{j,p}\)

\(n\le 10^5,d\le 30,2\le k\le 3\)

分析

考虑 \(k=2\) 怎么做。发现寻找一组解比较困难,考虑随机化。若无解,那么肯定满足 \(\forall i,j, a_i\cdot a_j\equiv 1\)。考虑随出一个集合 \(S\),并让集合 \(S\) 外的 \(i\)\(S\) 内的所有向量分别做点积并求和(模 \(k\) 意义下),若总和为 \(|S|\bmod k\),则这个 \(i\) 肯定与 \(S\) 内的某个点点乘后合法,暴力 check 即可。不难发现每次做一遍成功率至少为 \(\frac{1}{2}\),多做几次即可。复杂度 \(O(Knd)\)\(K\) 为随机次数。

考虑 \(k=3\)。这时无解,点积的结果可能为 \(1\)\(2\),相当的不好处理。但是注意到 \(1\)\(2\) 平方后的结果模 \(3\) 意义下均为 \(1\),把 \(\sum_{p=1}^d a_{i,p}a_{j,p}\) 转化为 \(\sum_{p=1}^d\sum_{q=1}^d a_{i,p}a_{i,q}a_{j,p}a_{j,q}\),这样就转化为了 \(d\leftarrow d^2\)\(k=2\),就好处理了。复杂度 \(O(Knd^2)\)

int n,m,d,k;
int a[maxn][maxm],b[maxms];
mt19937 rnd(time(0));
bool flag[maxn];
inline int get(int x,int y){
	return a[x][y/d]*a[x][y%d];
}
inline void solve_the_problem(){
	n=rd(),d=rd(),k=rd(),m=d*d;
	rep(i,1,n)rep(j,0,d-1)a[i][j]=rd()%k;
	rep(_,1,B){
		int tot=0;
		rep(i,1,n)flag[i]=rnd()%2,tot+=flag[i];
		rep(j,0,m-1)b[j]=0;
		rep(i,1,n)if(flag[i])rep(j,0,m-1)b[j]=(b[j]+get(i,j))%k;
		rep(i,1,n)if(!flag[i]){
			int sum=0;
			rep(j,0,m-1)sum=(sum+get(i,j)*b[j])%k;
			if(sum!=tot%k){
				rep(l,1,n)if(flag[l]){
					sum=0;
					rep(j,0,m-1)sum=(sum+get(i,j)*get(l,j))%k;
					if(!sum)return printf("%d %d",min(i,l),max(i,l)),void();
				}
			}
		}
	}
	printf("-1 -1");
}
posted @ 2025-01-19 15:10  dcytrl  阅读(46)  评论(0)    收藏  举报