luogu P1224 [NOI2013] 向量内积
比较妙妙的题目。
首先我们考虑\(k=2\),直接暴力没有优化方式,考虑随机化。
我们随机一个向量的排列方式,将第\(i\)个向量和前面的向量求出内积之和\(\bmod k\)的结果,如果这个结果不等于\((i-1)\bmod 2\),则说明前面一定有一个向量与它的内积为\(0\),则暴力检验即可。单个向量每次随机成功概率为\(\frac{1}{2}\),实际上多随几次就过了。
然后考虑\(k=3\),我们发现问题在于\(k=3\)乘积有\(1\)与\(2\)是不固定的,也就没有办法用上面那个方法判定前面是否一定有一个与其内积为\(0\)。但是我们又发现\(1^2\bmod k=2^2\bmod k\),则平方即可按照上面的方法做。时间复杂度\(O(nd^2T)\),\(T\)为随机轮数。
尽管取\(T=1\)就能过
code:
#include<bits/stdc++.h>
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((m)*(x-1)+(y))
#define R(n) (rnd()%(n))
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=1e5+5,M=100+5,K=(1<<10)+5,mod=1e9+7,Mod=mod-1;ll INF=1e18+7;const db eps=1e-5;mt19937 rnd(time(0));
int n,d,k,g[M][M],Ts;
struct Node{int A[M],id;}S[N];
void CK(Node x,Node y){ll Ts=0;for(int i=1;i<=d;i++) Ts+=x.A[i]*y.A[i];if(Ts%k==0) {printf("%d %d\n",min(x.id,y.id),max(x.id,y.id));exit(0);}}
int main(){
freopen("1.in","r",stdin);
int i,j,h;scanf("%d%d%d",&n,&d,&k);for(i=1;i<=n;S[i].id=i,i++) for(j=1;j<=d;j++) scanf("%d",&S[i].A[j]),S[i].A[j]%=k;
int T=1;while(T--){
Me(g,0);shuffle(S+1,S+n+1,rnd);for(i=1;i<=n;i++){
Ts=0;for(j=1;j<=d;j++) for(h=1;h<=d;h++) Ts+=g[j][h]*S[i].A[j]*S[i].A[h];if(Ts%k!=(i-1)%k){for(j=1;j<i;j++) CK(S[i],S[j]);cerr<<1<<'\n';}
for(j=1;j<=d;j++) for(h=1;h<=d;h++) g[j][h]=(S[i].A[j]*S[i].A[h]+g[j][h])%k;
}
}puts("-1 -1");
}