0314

jokeru000D發表於2024-03-15

[NOI2013] 向量內積


題目描述

兩個 \(d\) 維向量 \(A=[a_1,a_2,\ldots,a_d]\)\(B=[b_1,b_2,\ldots,b_d]\) 的內積為其相對應維度的權值的乘積和,即:

\[(A,B)=\sum_{i=1}^d a_ib_i=a_1b_1+a_2b_2+\ldots+a_db_d \]

現有 \(n\)\(d\) 維向量 \(x_1,\ldots,x_n\) ,小喵喵想知道是否存在兩個向量的內積為 \(k\) 的倍數。請幫助她解決這個問題。

輸入格式

第一行包含 \(3\) 個正整數 \(n,d,k\),分別表示向量的個數,維數以及待檢測的倍數。

接下來 \(n\) 行每行有 \(d\) 個非負整數,其中第 \(i\) 行的第 \(j\) 個整數表示向量 \(x_i\) 的第 \(j\) 維權值 \(x_{i,j}\)

輸出格式

包含兩個整數,用空格隔開。

如果存在兩個向量 \(x_p,x_q\) 的內積為 \(k\) 的整數倍,則輸出兩個向量的編號 \(p\)\(q\)(要求 \(p<q\))。如果存在多組這樣的向量組合,輸出其中任意一組即可。

若不存在這樣的向量組合,則輸出兩個 \(-1\)

樣例輸入 #1

3 5 2 
1 0 1 0 1 
1 1 0 1 0 
0 1 0 1 1

樣例輸出 #1

2 3

AC

觀察資料範圍,發現\(k=2或k=3\),可以分兩類

\(k=2\)
取模後結果為\(1\)\(0\),可以求每個向量與前面向量的和的內積,如果這個向量與前面的向量不符合題目要求那麼結果必然是\(1\),所以和必然是\((i-1) mod k\)

\(k=3\)
取模後結果是0,1,2,但是平方後再取模結果就是0,1。與\(k=2\)相同

#include<bits/stdc++.h>
using namespace std;
inline int readn()
{
	int x=0,f=1;
	char ch;
	while(ch<48||ch>57)
	{
		ch=getchar();
		if(ch==45)f=-1;
	}
	while(ch>=48&&ch<=57) 
	{
		x=(x<<3)+(x<<1)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
vector<signed> a[100005];
signed n,k,d;
signed k2[150];
signed k3[150][150];
signed solve(int x)
{
	int ans=0;
	if(k==2) for(register int i=0;i<d;i++)
	{
		ans^=a[x][i]&k2[i];
		k2[i]^=a[x][i];
	}
	else for(register int i=0;i<d;i++)
		for(register int j=0;j<d;j++)
		{
			ans+=a[x][i]*a[x][j]*k3[i][j]%k;
			k3[i][j]+=a[x][i]*a[x][j];
		}
	return ans%k;
}
signed main()
{
	n=readn();
	d=readn();
	k=readn();
	for(register int i=1;i<=n;i++)
	{
		for(register int j=1;j<=d;j++)
		{
			a[i].push_back(readn()%k);
		}
	}
	int ans;
	for(register int i=1;i<=n;i++)
		if(solve(i)!=(i-1)%k)
			for(register int l=1;l<i;l++)
			{
				ans=0;
				for(register int p=0;p<d;p++)ans+=a[l][p]*a[i][p];
				if(ans%k==0)
				{
					printf("%d %d",l,i);
					return 0;
				}
			}
	printf("-1 -1");
    return 0;
}

Collective Mindsets(hard)


題目描述

一共有 \(n\) 個殭屍,每個殭屍頭上有一個 \(1 \sim n\) 之間的數字(可重複!),每個殭屍只能看到其他 \(n - 1\) 個殭屍頭頂的數字,當然,他們也知道自己的編號。 要求提供一種策略,使所有殭屍只利用自己知道的資訊同時猜自己頭頂的數字,保證至少有一個殭屍猜對。

輸入格式

第一行,一個正整數 \(T\),表示資料組數。

接下來對於每組資料,第一行包含兩個正整數 \(n\)\(r\),表示殭屍總數與當前殭屍的編號,下一行包括 \(n-1\) 個正整數,表示當前殭屍看到的所有其他殭屍頭頂的編號是多少(按殭屍編號升序排列)。

輸出格式

對於每組資料輸出一行一個整數,表示該殭屍的猜測。

資料範圍

\(1 \le T \le 50000\)\(2 \le n \le 6\)\(1 \le r \le n\)

樣例輸入 #1

4
2 1
1
2 2
1
2 1
2
2 2
2

樣例輸出 #1

1
2
2
1

樣例輸入 #2

2
5 2
2 2 2 2
6 4
3 2 6 1 2

樣例輸出 #2

5
2

做法

總共有n個殭屍,頭上只有n個號碼,無論哪種方法,猜中的機率都是一定的,所以應該不重複的把所有情況猜一遍所以可以設除第\(R\)個人的數之和為\(sum\),讓這個猜\((sum+r)mod n\)每個人都如此,就不會有重複的情況

#include<iostream>
using namespace std;
int n,r,x,ans;
int T;
int j;
int main()
{
	cin>>T;
	while(T--)
	{
		ans=0;
		cin>>n>>r;
		for(int i=1;i<n;i++)
		{
			cin>>x;
			ans+=x;
		}
		j=0;
		while((j+ans)%n!=r%n)j++;
		cout<<j+1<<endl;
	}
    return 0;
}

相關文章