【NOI2013】【BZOJ3243】向量内积

Description

两个d 维向量A=[a1,a2,…,ad]与B=[b1,b2,…,bd]的内积为其相对应维度的权值的乘积和,即:
这里写图片描述
现有 n 个d 维向量x1,…,xn ,小喵喵想知道是否存在两个向量的内积为k的倍数。请帮助她解决这个问题
Input

第一行包含3个正整数n,d,k,分别表示向量的个数,维数以及待检测的倍数。
接下来n行每行有d个非负整数,其中第i行的第j个整数表示向量xi的第j维权值xi,j。
Output

包含两个整数,用空格隔开。
如果存在两个向量xp,xq的内积为k的整数倍,则输出两个向量的编号p与q(要求p< q)。如果存在多组这样的向量组合,输出其中任意一组即可。
若不存在这样的向量组合,则输出两个-1。
Sample Input
Sample Output
HINT
这里写图片描述
Source

不会做QAQ
Mektpoy题解
感觉好厉害啊…竟然是转成矩阵来做T_T
取模会导致跑得慢.我的代码里注释掉的那种只跑了2400ms,没注释掉的跑了6600msQAQ

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define GET (ch>='0'&&ch<='9')
#define MAXN 100100
using namespace std;
int n,d,k;
bool flag;
int a[MAXN][110],sum[MAXN],b[MAXN],c[MAXN],top,num[110][110];
int f,ans;
void in(int &x)
{
    x=0;char ch=getchar();int flag=1;
    while (!GET)    flag=ch=='-'?-1:1,ch=getchar();
    while (GET) x=x*10+ch-'0',ch=getchar();x*=flag;
}
bool check(int i,int j)
{
    int ret=0;
    for (int l=1;l<=d;l++)  ret+=a[i][l]*a[j][l],ret%=k;
    return !ret;
}
int main()
{
    in(n);in(d);in(k);
    for (int i=1;i<=n;i++)
        for (int j=1;j<=d;j++)  in(a[i][j]),a[i][j]%=k,sum[i]+=a[i][j]*a[i][j],sum[i]%=k;
    /*for (int i=1;i<=n;i++)
        for (int j=1;j<=d;j++)  in(a[i][j]),a[i][j]%=k,sum[i]+=a[i][j]*a[i][j];
    for (int i=1;i<=n;i++)  sum[i]%=k;*/
    if (k==2)
    {
        for (int i=1;i<=n;i++)
            for (int j=1;j<=d;j++)  b[j]+=a[i][j],b[j]%=k;
        for (int i=1;i<=n;i++)
            for (int j=1;j<=d;j++)  c[i]+=a[i][j]*b[j],c[i]%=k;
        for (int i=1;i<=n;i++)  c[i]=(c[i]-sum[i]+k)%k;f=(n-1)%k;
        /*for (int i=1;i<=n;i++)
            for (int j=1;j<=d;j++)  b[j]+=a[i][j];
        for (int i=1;i<=d;i++)  b[i]%=k;
        for (int i=1;i<=n;i++)
            for (int j=1;j<=d;j++)  c[i]+=a[i][j]*b[j];
        for (int i=1;i<=n;i++)  c[i]=(c[i]%k-sum[i]+(k<<1))%k;f=(n-1)%k;*/
    }
    else
    {
        for (int i=1;i<=d;i++)
            for (int j=1;j<=d;j++)  num[i][j]=++top;
        /*for (int i=1;i<=n;i++)
            for (int j=1;j<=d;j++)
                for (int l=1;l<=d;l++)  b[num[j][l]]+=a[i][j]*a[i][l];
        for (int i=1;i<=top;i++)    b[i]%=k;
        for (int i=1;i<=n;i++)
            for (int j=1;j<=d;j++)  
                for (int l=1;l<=d;l++)  c[i]+=a[i][j]*a[i][l]*b[num[j][l]];
        for (int i=1;i<=n;i++)  c[i]=(c[i]%k-sum[i]*sum[i]+(k<<1))%k;f=(n-1)%k;*/
        for (int i=1;i<=n;i++)
            for (int j=1;j<=d;j++)
                for (int l=1;l<=d;l++)  b[num[j][l]]+=a[i][j]*a[i][l],b[num[j][l]]%=k;
        for (int i=1;i<=n;i++)
            for (int j=1;j<=d;j++)  
                for (int l=1;l<=d;l++)  c[i]+=a[i][j]*a[i][l]*b[num[j][l]],c[i]%=k;
        for (int i=1;i<=n;i++)  c[i]=(c[i]-sum[i]*sum[i]+k)%k;f=(n-1)%k;
    }
    for (int i=1;i<=n;i++)
    {
        if (flag)   break;
        if (f!=c[i])    flag=1,ans=i;
    }
    if (!flag)  {puts("-1 -1");return 0;}
    for (int i=1;i<=n;i++)
        if (ans!=i&&check(ans,i))   {printf("%d %d\n",min(ans,i),max(ans,i));return 0;}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值