BZOJ3243 NOI2013向量内积(随机化)
考虑奇技淫巧。
首先是k=2。对向量维护一个前缀和,每次将当前向量与前缀和点乘。如果点乘结果不等于i-1&1,说明当前向量至少和之前的某个向量的数量积是2的倍数,暴力找就可以了。当然等于i-1&1也不一定就不存在,这本质上还是个随机算法,于是先random_shuffle一下。
k=3时,注意到12≡22≡1(mod 3),于是维护一个平方前缀和。具体的化一下式子就可以得出。
调了半天才发现bzoj题面上的数据范围锅了。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<ctime> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 100010 #define D 110 int n,d,k,a[N][D],b[D],c[D][D],id[N]; int main() { #ifndef ONLINE_JUDGE freopen("bzoj3243.in","r",stdin); freopen("bzoj3243.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif 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<=n;i++) id[i]=i; srand(time(0)); random_shuffle(id+1,id+n+1); if (k==2) { for (int i=1;i<=d;i++) b[i]=a[id[1]][i]; for (int i=2;i<=n;i++) { int tot=0; for (int j=1;j<=d;j++) tot+=a[id[i]][j]&b[j]; if ((tot&1)!=(i-1&1)) { for (int j=1;j<i;j++) { int tot=0; for (int k=1;k<=d;k++) tot+=a[id[i]][k]&a[id[j]][k]; if (tot%2==0) {cout<<min(id[i],id[j])<<' '<<max(id[i],id[j])<<endl;return 0;} } } for (int j=1;j<=d;j++) b[j]=b[j]+a[id[i]][j]&1; } } else { for (int i=1;i<=d;i++) for (int j=1;j<=d;j++) c[i][j]=a[id[1]][i]*a[id[1]][j]%3; for (int i=2;i<=n;i++) { int tot=0; for (int j=1;j<=d;j++) for (int k=1;k<=d;k++) tot+=a[id[i]][j]*a[id[i]][k]*c[j][k]; if (tot%3!=(i-1)%3) { for (int j=1;j<i;j++) { int tot=0; for (int k=1;k<=d;k++) for (int l=1;l<=d;l++) tot+=a[id[i]][k]*a[id[i]][l]*a[id[j]][k]*a[id[j]][l]; if (tot%3==0) {cout<<min(id[i],id[j])<<' '<<max(id[i],id[j])<<endl;return 0;} } } for (int j=1;j<=d;j++) for (int k=1;k<=d;k++) c[j][k]=(c[j][k]+a[id[i]][j]*a[id[i]][k])%3; } } cout<<-1<<' '<<-1; return 0; }