【XSY3126】异或II 数学

题目描述

  给你一个序列 \(a_0,a_1,\ldots,a_{n-1}\)。你要进行 \(t\) 次操作,每次操作是把序列 \(x\) 变为序列 \(y\),满足 \(y_i=\oplus_{j=0}^{k-1}x_{(i+j)\bmod n}\)\(\oplus\) 表示异或。

  求 \(t\) 次操作后的序列。

  \(1\leq k\leq n\leq 500000,t\leq {10}^{18}\)

题解

  设 \(f_{i,j}\) 为原序列进行 \(i\) 次操作后是哪些数的异或和。

  设 \(F_i(x)=\sum_{j=0}^{n-1}f_{i,j}x^j\)

  那么 \(F_i(x)=(1+x+\cdots x^{k-1})F_{i-1}(x)\)

  注意到模 \(2\) 意义下的多项式的平方是很好求的,只需要把所有 \(x^i\) 改成 \(x^{2i}\) 就好了。因为其他项的系数都是 \(2\)的倍数。

  所以 \(F_{2^t}(x)=1+x^{2^t}+\cdots+x^{(k-1)2^t}\),那么乘上 \(F_{2^t}(x)\) 就是

\[y_i=\oplus_{j=0}^{k-1}x_{(i+j\times 2^t)\bmod n} \]

  然后暴力算就可以了。

  时间复杂度:\(O(n\log t)\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<functional>
#include<cmath>
#include<vector>
//using namespace std;
using std::min;
using std::max;
using std::swap;
using std::sort;
using std::reverse;
using std::random_shuffle;
using std::lower_bound;
using std::upper_bound;
using std::unique;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef std::pair<int,int> pii;
typedef std::pair<ll,ll> pll;
void open(const char *s){
#ifndef ONLINE_JUDGE
	char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout);
#endif
}
int rd(){int s=0,c,b=0;while(((c=getchar())<'0'||c>'9')&&c!='-');if(c=='-'){c=getchar();b=1;}do{s=s*10+c-'0';}while((c=getchar())>='0'&&c<='9');return b?-s:s;}
void put(int x){if(!x){putchar('0');return;}static int c[20];int t=0;while(x){c[++t]=x%10;x/=10;}while(t)putchar(c[t--]+'0');}
int upmin(int &a,int b){if(b<a){a=b;return 1;}return 0;}
int upmax(int &a,int b){if(b>a){a=b;return 1;}return 0;}
const int N=500010;
bool c[N];
int a[N];
int b[N];
int d[N];
int n,k;
ll m;
int gcd(int a,int b)
{
	return b?gcd(b,a%b):a;
}
int cnt;
int plus(int a,int b)
{
	a+=b;
	return a>=n?a-n:a;
}
int minus(int a,int b)
{
	a-=b;
	return a<0?a+n:a;
}
void gao(int t)
{
	if(!t)
		return;
	memset(c,0,sizeof c);
	memcpy(b,a,sizeof a);
	int kk=k%(2*n/gcd(t,n));
	for(int i=0;i<n;i++)
		if(!c[i])
		{
			cnt=0;
			for(int j=i;!c[j];j=plus(j,t))
				d[++cnt]=j,c[j]=1;
			int s=0;
			int now=d[cnt];
			for(int j=0;j<kk;j++,now=plus(now,t))
				s^=b[now];
			a[d[cnt]]=s;
			for(int j=cnt-1;j>=1;j--)
			{
				now=minus(now,t);
				s^=b[d[j]];
				s^=b[now];
				a[d[j]]=s;
			}
		}
}
int main()
{
	open("b");
	scanf("%d%d%lld",&n,&k,&m);
	for(int i=0;i<n;i++)
		a[i]=rd();
	for(ll i=1;i<=m;i<<=1)
		if(m&i)
			gao(i%n);
	for(int i=0;i<n;i++)
		printf("%d ",a[i]);
	return 0;
}
posted @ 2018-07-01 17:25  ywwyww  阅读(434)  评论(0编辑  收藏  举报