1. 程式人生 > 實用技巧 >2020.11.25 考試題解

2020.11.25 考試題解

T2

【題目描述】

有一圈數,其數目為n個,定義一次操作為每個數變為原數圈中的自己與相鄰的兩個數這三個數的異或和,給出原陣列和操作次數,請算出最後的結果陣列。


【輸入資料】

輸入第一行包含兩個正整數n和k,分別表示陣列數目和操作次數。第二行$n$個整數。


【輸出資料】

僅包含一行n個整數。

樣例輸入:

3 1
1 2 3

樣例輸出:

0 0 0

資料範圍:

對於\(30%\)的資料,\(n\times k\leq 10^8\)

對於\(100%\)的資料,\(1\leq n\leq 10^5,1\leq k\leq 10^9\)

分析:

對於\(a_i\),進行一次操作後,會變為\(a_{i-1}\)

^\(a_i\)^\(a_{i+1}\)

兩次操作後,會變為\(a_{i-2}\)^\(a_i\)^\(a_{i+2}\)

三次操作後,會變為\(a_{i-3}\)^\(a_{i-2}\)^\(a_i\)^\(a_{i+2}\)^\(a_{i+3}\)

四次操作後,會變為\(a_{i-4}\)^\(a_i\)^\(a_{i+4}\)

我們發現當操作次數為\(2^k\)時,\(a_i\)會變為\(a_{i-{2^k}}\)^\(a_i\)^\(a_{i+{2^k}}\)

由此,我們可以將\(k\)次操作進行二進位制分解,一定可以完全分解,將\(k\)降為\(log_k\),每次\(O(n)\)暴力操作,時間複雜度為\(O(n\times log_k)\)

\(Code:\)

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define vocaloid(v) (v>='0'&&v<='9')
template <typename T>
il void read(T &x)
{
	x=0;char v=getchar();
	while(!vocaloid(v)) v=getchar();
	while(vocaloid(v)) {x=(x<<1)+(x<<3)+v-'0';v=getchar();}
}
template <typename T>
il void write(T x)
{
	if(x>9) write(x/10);
	putchar(x%10+'0');
}
int n,k,a[100039],b[10039];
int main()
{
	freopen("xor.in","r",stdin);
	freopen("xor.out","w",stdout);
	read(n),read(k);
	for(int i=1;i<=n;i++) read(a[i]);
	for(int pos=1;k;pos<<=1,k>>=1)
	{
		if(k&1)
		{
			for(int i=1;i<=n;i++) b[i]=a[i];
			for(int l=((-pos%n)+n)%n+1,r=(pos%n)+1,i=1;i<=n;i++)
			{
				a[i]^=b[l++]^b[r++];
				if(l>n) l=1;
				if(r>n) r=1;
			}
		}
	}
	for(int i=1;i<=n;i++) write(a[i]),putchar(' ');
	return 0;
}