2020.11.25 考试题解

T2

【题目描述】

有一圈数,其数目为n个,定义一次操作为每个数变为原数圈中的自己与相邻的两个数这三个数的异或和,给出原数组和操作次数,请算出最后的结果数组。


【输入数据】

输入第一行包含两个正整数n和k,分别表示数组数目和操作次数。第二行$n$个整数。


【输出数据】

仅包含一行n个整数。

样例输入:

3 1
1 2 3

样例输出:

0 0 0

数据范围:

对于(30%)的数据,(n imes kleq 10^8)

对于(100%)的数据,(1leq nleq 10^5,1leq kleq 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 imes 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;
}
原文地址:https://www.cnblogs.com/MIKU5201314/p/14086739.html