题目传送门
题面
题目背景
](https://www.luogu.com.cn/paste/tdqr0sto)
可怜的 dead_X 收不了歌,于是他出了个水题并给参赛者送了 100 100 100 分。
2022 Update: 已经收了,很水。
题目描述
你需要维护一个序列。
这个序列开始时有 2 n 2^n 2n 个数,下标从 0 0 0 开始。第 i i i 个数初始值为 i i i,需要支持以下三种操作:
- 定义 a a a 为所有下标为偶数的数组成的子序列, b b b 为所有下标为奇数的数组成的子序列,将 a , b a,b a,b 连接,构成新的序列。
- 定义 a a a 为所有下标为奇数的数组成的子序列, b b b 为所有下标为偶数的数组成的子序列,将 a , b a,b a,b 连接,构成新的序列。
- 查询下标为 x x x 的数。
总共将进行 m m m 次操作。
输入格式
第一行输入两个正整数 n , m n,m n,m。
接下来输入 m m m 行,每行输入两个非负整数 o p , x op,x op,x,代表一次操作。
如果 o p = 1 op=1 op=1,若 x = 0 x=0 x=0,代表第一种操作,若 x = 1 x=1 x=1,代表第二种操作。
如果 o p = 2 op=2 op=2,代表第三种操作,参数 x x x 即为输入的 x x x。
输出格式
对于每个 o p = 2 op=2 op=2 输出一行,即对应的数。
输入输出样例 #1
输入 #1
2 7
2 0
1 0
2 1
1 1
2 2
1 0
2 3
输出 #1
0
2
0
1
说明/提示
【样例解释】
所有操作前后的序列从左至右的数如下:
{
0
,
1
,
2
,
3
}
\{0,1,2,3\}
{0,1,2,3}
下标为
0
0
0 的数为
0
0
0。
{
0
,
2
}
,
{
1
,
3
}
\{0,2\},\{1,3\}
{0,2},{1,3}
{
0
,
2
,
1
,
3
}
\{0,2,1,3\}
{0,2,1,3}
下标为
1
1
1 的数为
2
2
2。
{
2
,
3
}
,
{
0
,
1
}
\{2,3\},\{0,1\}
{2,3},{0,1}
{
2
,
3
,
0
,
1
}
\{2,3,0,1\}
{2,3,0,1}
下标为
2
2
2 的数为
0
0
0。
{
2
,
0
}
,
{
3
,
1
}
\{2,0\},\{3,1\}
{2,0},{3,1}
{
2
,
0
,
3
,
1
}
\{2,0,3,1\}
{2,0,3,1}
下标为
3
3
3 的数为
1
1
1。
【数据范围】
本题采用捆绑测试。
- Subtask 1(10 points):不存在 o p = 1 op=1 op=1 的操作。
- Subtask 2(10 points): n ≤ 10 , m ≤ 1 0 3 n\leq 10,m\leq 10^3 n≤10,m≤103。
- Subtask 3(20 points): n ≤ 10 n\leq 10 n≤10。
- Subtask 4(20 points): m ≤ 1 0 3 m\leq 10^3 m≤103。
- Subtask 5(20 points):对于 o p = 1 op=1 op=1 的操作, x = 0 x=0 x=0。
- Subtask 6(20 points):无特殊限制。
对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 32 1\leq n\leq 32 1≤n≤32, 1 ≤ m ≤ 1 0 6 1\leq m\leq 10^6 1≤m≤106。
若 o p = 1 op=1 op=1, x ∈ { 0 , 1 } x\in\{0,1\} x∈{0,1},若 o p = 2 op=2 op=2, 0 ≤ x < 2 n 0\leq x<2^n 0≤x<2n。
题目解析
给你一个长度为 2 n 2^n 2n 的序列,下标从 0 0 0 开始,初始时每个元素的值等于他的下标。执行以下操作:
- 将下标为奇数的元素子序列接到下标为偶数的元素后。
- 将下标为偶数的元素子序列接到下标为奇数的元素后。
- 求下标 x x x 的元素的值。
思路
标签:位运算。
我们遇见这种显然不能暴力的题目,要先把样例画出来,或者自己找一下规律。
以 n = 2 n = 2 n=2 为例,原式为 { 0 , 1 , 2 , 3 } \{ 0,1,2,3 \} {0,1,2,3}。
执行操作 1 1 1 后,原式为 { 0 , 2 , 1 , 3 } \{ 0,2,1,3 \} {0,2,1,3}。
执行操作 2 2 2 后,原式为 { 1 , 3 , 0 , 2 } \{ 1,3,0,2 \} {1,3,0,2}。
执行操作 1 1 1 再执行操作 2 2 2 后,原式为 { 2 , 3 , 0 , 1 } \{ 2,3,0,1 \} {2,3,0,1}。
把这四个式子转成二进制:
- 00 , 01 , 10 , 11 00,01,10,11 00,01,10,11
- 00 , 10 , 01 , 11 00,10,01,11 00,10,01,11
- 01 , 11 , 00 , 10 01,11,00,10 01,11,00,10
- 10 , 11 , 00 , 01 10,11,00,01 10,11,00,01
发现什么没有?操作 1 1 1 相当于把二进制的最高位转到最低位,操作 2 2 2 则是在操作 1 1 1 的基础上异或 1 1 1 。你可以试试再打一下 n = 3 n = 3 n=3 的情况,这里不再赘述。
所以我们记录当前转了 x x x 次和结果要异或 y y y。如果 x = n x = n x=n 次就归零。我们可以看见第四个式子其实是异或了 2 2 2 的,这是为什么呢?转了一次之后,原本 1 1 1 的位置就会左移,所以我们对于每个 2 2 2 操作要做 y ← y ⊕ 2 x y \leftarrow y \oplus 2^x y←y⊕2x ,再把 x x x 加上一。
最后的输出怎么处理呢?原本下标 x x x 处的值就是 x x x ,然后原本的数字我们先右移 n − x n - x n−x 位,表示将前 x x x 位移动到末尾,然后把原数与 2 n − x − 1 2 ^ {n - x} - 1 2n−x−1 取按位与得到没有被移到末尾的数,把他们左移 x x x 位。最后把两个值取按位或,在与 y y y 取按位异或即可。注意特判 x = 0 x = 0 x=0 的情况,这时只需将原数与 y y y 按位异或即可。
公式就是 ( x ≫ ( n − x ) ) ∣ ( ( x & ( ( 1 ≪ ( n − x ) ) − 1 ) ) ≪ x ) ⊕ y (x \gg (n - x)) | ((x \& ((1 \ll (n - x)) - 1)) \ll x) \oplus y (x≫(n−x))∣((x&((1≪(n−x))−1))≪x)⊕y 。
CODE
#include<iostream>
#define int long long
using namespace std;
int n,m;
int turn,xors;
signed main()
{
cin >> n >> m;
while(m--)
{
int op,x;
cin >> op >> x;
if(op == 1)
{
if(x) xors ^= (1ll << turn);
turn++;
turn %= n;
}
else
{
if(turn)
{
cout << (((x >> (n - turn)) | ((x & ((1ll << (n - turn)) - 1)) << turn)) ^ xors);
}
else cout << (x ^ xors);
cout << '\n';
}
}
}
825

被折叠的 条评论
为什么被折叠?



