题目
题目描述
定义一个从序列到序列的映射
f
(
a
)
=
b
f(a)=b
f(a)=b 满足
b
i
=
⨁
j
=
0
k
−
1
a
(
i
+
j
)
m
o
d
n
b_i=\bigoplus_{j=0}^{k-1}a_{(i+j)\bmod n}
bi=j=0⨁k−1a(i+j)modn
其中 a , b a,b a,b 都是下标在 0 0 0 到 n − 1 n{-}1 n−1 之间的非负整数序列。
现在你需要求出 f T ( a ) = f T − 1 [ f ( a ) ] ( T > 1 ) f^T(a)=f^{T-1}[f(a)]\;(T>1) fT(a)=fT−1[f(a)](T>1),规定 f 1 ( a ) = f ( a ) f^1(a)=f(a) f1(a)=f(a) 。即对 a a a 进行 T T T 次 f f f 变换后的结果。
数据范围与提示
n
⩽
5
×
1
0
5
,
T
⩽
1
0
18
n\leqslant 5\times 10^5,\;T\leqslant 10^{18}
n⩽5×105,T⩽1018 。
思路
直接快速幂不可以过。但是很特殊的是,我们快速幂只是在求
(
1
+
x
+
x
2
+
⋯
+
x
k
−
1
)
T
m
o
d
2
\left(1+x+x^2+\cdots+x^{k-1}\right)^T\bmod 2
(1+x+x2+⋯+xk−1)Tmod2
显然这个式子等于
(
1
−
x
k
1
−
x
)
T
=
[
∑
i
=
0
T
(
T
i
)
(
−
1
)
i
x
i
k
]
[
∑
i
=
0
+
∞
(
i
+
T
−
1
T
−
1
)
x
i
]
\left(\frac{1-x^k}{1-x}\right)^T=\left[\sum_{i=0}^{T}{T\choose i}(-1)^ix^{ik}\right]\left[\sum_{i=0}^{+\infty}{i+T-1\choose T-1}x^i\right]
(1−x1−xk)T=[i=0∑T(iT)(−1)ixik][i=0∑+∞(T−1i+T−1)xi]
即分子分母都展开的结果。这个式子感觉不好整,因为组合数太复杂了……
不过,既然是模
2
2
2 意义下,很容易让人想起卢卡斯定理,
(
n
m
)
m
o
d
2
=
[
m
⊆
n
]
{n\choose m}\bmod 2=\big[m\subseteq n\big]
(mn)mod2=[m⊆n]
这里用集合符号表示了二进制位的情况。即 m m m 与 n n n 的按位与结果是 m m m 。
不妨设
T
=
2
t
(
t
⩾
1
)
T=2^t\;(t\geqslant 1)
T=2t(t⩾1),那么左边那个括号只有两项,右边那个括号只有
2
t
∣
i
2^t\mid i
2t∣i 的项。于是
≡
(
1
+
x
2
t
k
)
(
∑
i
=
0
+
∞
x
2
t
i
)
≡
1
+
x
2
t
+
x
2
t
×
2
+
⋯
+
x
2
t
(
k
−
1
)
(
m
o
d
2
)
\equiv(1+x^{2^tk})\left(\sum_{i=0}^{+\infty}x^{2^ti}\right)\\ \equiv 1+x^{2^t}+x^{2^t\times 2}+\cdots+x^{2^t(k-1)}\pmod 2
≡(1+x2tk)(i=0∑+∞x2ti)≡1+x2t+x2t×2+⋯+x2t(k−1)(mod2)
这个东西就很有规律了——以 2 t 2^t 2t 为步长,每个点变为前面 k k k 步的值的异或值。作个 2 t 2^t 2t 步长的前缀和,进行一次这种变换就是 O ( n ) \mathcal O(n) O(n) 的了。
问题只是 T T T 不是二的幂;二进制拆分就完了。复杂度 O ( n log T ) \mathcal O(n\log T) O(nlogT) 。
代码
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
typedef long long int_;
inline int readint(){
int a = 0; char c = getchar(), f = 1;
for(; c<'0'||c>'9'; c=getchar())
if(c == '-') f = -f;
for(; '0'<=c&&c<='9'; c=getchar())
a = (a<<3)+(a<<1)+(c^48);
return a*f;
}
inline void writeint(int x){
if(x > 9) writeint(x/10);
putchar((x-x/10*10)^48);
}
const int MaxN = 500005;
int a[MaxN], b[MaxN], n, k;
bool vis[MaxN]; // the index
void change(long long T){
if((T %= n) == 0){
if(k&1) return ; // make no difference
memset(a,0,n<<2); return ;
}
memset(vis,0,n); // clear
for(int x=0; !vis[x]; ++x){
int p = 0, all = 0;
for(int i=x; !vis[i]; i=(i+T)%n)
all ^= a[i], ++ p, vis[i] = 1;
int now = 0, fr = (x+k*T)%n;
for(int i=x; i!=fr; i=(i+T)%n)
now ^= a[i]; // k-th number
for(int i=fr; true; i=(i+T)%n){
now ^= a[(i-k*T%n+n)%n];
b[i] = (now ^= a[i]);
if((k/p)&1) b[i] ^= all;
if((i+T)%n == fr) break;
}
}
memcpy(a,b,n<<2); // copy back
}
int main(){
n = readint(), k = readint();
long long T; scanf("%lld",&T);
for(int i=0; i<n; ++i)
a[n-1-i] = readint();
while(T) change(T&-T), T ^= (T&-T);
writeint(a[n-1]);
for(int i=1; i<n; ++i){
putchar(' ');
writeint(a[n-1-i]);
}
return 0;
}
后记
更强力的关系是
F
(
x
)
p
m
o
d
p
=
F
(
x
p
)
(
p
∈
P
)
F(x)^p\bmod p=F(x^p)\;(p\in{\Bbb P})
F(x)pmodp=F(xp)(p∈P),其中
P
\Bbb P
P 是质数集。证明方法也是利用卢卡斯定理:当
F
(
x
)
F(x)
F(x) 是单项式时,显然成立;当
F
(
x
)
F(x)
F(x) 有至少两项时,肯定可以拆成
G
(
x
)
+
H
(
x
)
G(x)+H(x)
G(x)+H(x),于是
[
G
(
x
)
+
H
(
x
)
]
p
=
∑
i
=
0
p
(
p
i
)
⋅
G
(
x
)
i
⋅
H
(
x
)
p
−
i
\big[G(x)+H(x)\big]^p=\sum_{i=0}^{p}{p\choose i}\cdot G(x)^i\cdot H(x)^{p-i}
[G(x)+H(x)]p=i=0∑p(ip)⋅G(x)i⋅H(x)p−i
只有
i
∈
{
0
,
p
}
i\in\{0,p\}
i∈{0,p} 时
(
p
i
)
m
o
d
p
≠
0
{p\choose i}\bmod p\ne 0
(ip)modp=0,所以其实
F
(
x
)
p
≡
G
(
x
)
p
+
H
(
x
)
p
(
m
o
d
p
)
F(x)^p\equiv G(x)^p+H(x)^p\pmod{p}
F(x)p≡G(x)p+H(x)p(modp)
根据归纳法(项数从小到大),我们推出
F
(
x
)
p
≡
G
(
x
p
)
+
H
(
x
p
)
=
F
(
x
p
)
(
m
o
d
p
)
F(x)^p\equiv G(x^p)+H(x^p)=F(x^p)\pmod{p}
F(x)p≡G(xp)+H(xp)=F(xp)(modp)
如果取
F
(
x
)
=
f
(
x
)
p
≡
f
(
x
p
)
(
m
o
d
p
)
F(x)=f(x)^p\equiv f(x^p)\pmod{p}
F(x)=f(x)p≡f(xp)(modp),你就得到了有趣的结论
[
f
(
x
)
p
]
p
≡
f
(
x
p
)
p
(
m
o
d
p
)
⇒
f
(
x
)
p
2
≡
f
(
x
p
2
)
(
m
o
d
p
)
[f(x)^p]^p\equiv f(x^p)^p\pmod{p}\\ \Rightarrow f(x)^{p^2}\equiv f(x^{p^2})\pmod{p}
[f(x)p]p≡f(xp)p(modp)⇒f(x)p2≡f(xp2)(modp)
多迭代几次,你就会得到本题中使用的式子。本题是
p
=
2
p=2
p=2 的特殊情况。
f
(
x
)
p
t
=
f
(
x
p
t
)
f(x)^{p^t}=f\left(x^{p^t}\right)
f(x)pt=f(xpt)
2022/8/5 update \texttt{2022/8/5 update} 2022/8/5 update:该式子也可以用二项式系数直接计算得到,但现在看来,似乎还没有这种构造方法简洁 😄