这个题用特征法可以比较好的找到思路
首先这个题有两个特征:1、正+反=反 反+正=反 正+正=正 反+反=正 应该能很快想到亦或
2、范围1e5 + 上限2^60 应该能很快想到倍增
然后就可以考虑一次求出一位的答案,一位的答案显然对应原始序列一段连续区间的亦或值,手动统计次数可以发现是组合数次数
如:
0
0 0
1 1 0 0
次数:1 3 3 1
0= 1^(1^1^1)^(1^1^1)^1 = 0
然后就发现只有组合数对应结果是奇数时才有帮助
这时候就可以考虑倍增。。 偶然发现,2^n的组合数只有两边是1,其他都是偶数。。
于是就倍增构造了。。
码:
#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
ll n,k,i,j,er[70],a[100005],b[100005];
int main()
{
scanf("%lld%lld",&n,&k);
for(i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
a[i]--;
}
a[0]=a[n];
er[0]=1;
for(i=1;i<=62;i++)
er[i]=(er[i-1]*2);
for(i=0;i<=62;i++)//枚举位
{
if(!(k&er[i]))continue;
for(j=1;j<=n;j++)
{
int z1=j,z2=(j+er[i]%n)%n;
b[j]=a[z1]^a[z2];
}
for(j=1;j<=n;j++)a[j]=b[j];
a[0]=b[n];
}
bool jo=k&1;
k/=2;
for(i=1;i<=n;i++)
{
if((i+k)%n==0)
{
b[n]=a[i];
}else b[(i+k)%n]=a[i];
}
if(jo)
{
for(i=1;i<n;i++)
printf("0 %d ",b[i]+1);
printf("0 %d",b[n]+1);
}else
{
for(i=1;i<n;i++)
printf("%d 0 ",b[i]+1);
printf("%d 0",b[n]+1);
}
}