P9741 翻转与反转
「KDOI-06-J」翻转与反转
题目描述
小 W 有一个长度为 n n n 的 01 01 01 序列 a 1 , a 2 , … , a n a_1,a_2,\ldots,a_n a1,a2,…,an,他将对这个序列按顺序进行 n n n 次操作。
在第 i i i 次操作中( 1 ≤ i ≤ n 1\le i\le n 1≤i≤n),小 W 将按顺序执行以下两种变换:
- 将区间 [ 1 , i ] [1,i] [1,i] 中的数按下标翻转。形式化地说,在这次变换之后,序列 a a a 将变为 a i , a i − 1 , … , a 1 , a i + 1 , a i + 2 , … , a n a_i,a_{i-1},\ldots,a_{1},a_{i+1},a_{i+2},\ldots,a_n ai,ai−1,…,a1,ai+1,ai+2,…,an。
- 将区间 [ 1 , i ] [1,i] [1,i] 中的数按值翻转。形式化地说,在这次变换之后,对于任意 1 ≤ j ≤ i 1\le j\le i 1≤j≤i,若 a j = 0 a_j=0 aj=0,则 a j a_j aj 将变为 1 1 1,否则 a j a_j aj 将变为 0 0 0。
小 W 想要知道,在全部 n n n 次操作结束后,序列 a a a 中每个元素的值。
输入格式
从标准输入读入数据。
输入的第一行包含一个正整数 n n n,表示序列长度。
接下来一行 n n n 个整数,表示序列 a 1 , a 2 , … , a n a_1,a_2,\ldots, a_n a1,a2,…,an。保证 a i = 0 a_i=0 ai=0 或 1 1 1。
输出格式
输出到标准输出。
输出包含一行 n n n 个整数,表示操作结束后序列 a a a 中每个元素的值。
样例 #1
样例输入 #1
3
1 1 1
样例输出 #1
0 0 1
样例 #2
样例输入 #2
8
1 0 1 1 1 0 0 1
样例输出 #2
0 1 0 1 1 1 1 0
提示
【样例解释 #1】
序列 a a a 的变化如下表所示:
操作次数 | 序列 a a a 的变化 |
---|---|
1 1 1 | [ 1 , 1 , 1 ] → [ 1 , 1 , 1 ] → [ 0 , 1 , 1 ] [1,1,1]\to [1,1,1]\to[0,1,1] [1,1,1]→[1,1,1]→[0,1,1] |
2 2 2 | [ 0 , 1 , 1 ] → [ 1 , 0 , 1 ] → [ 0 , 1 , 1 ] [0,1,1]\to [1,0,1]\to[0,1,1] [0,1,1]→[1,0,1]→[0,1,1] |
3 3 3 | [ 0 , 1 , 1 ] → [ 1 , 1 , 0 ] → [ 0 , 0 , 1 ] [0,1,1]\to [1,1,0]\to[0,0,1] [0,1,1]→[1,1,0]→[0,0,1] |
【样例解释 #2】
序列 a a a 的变化如下表所示:
操作次数 | 操作后的序列 a a a |
---|---|
- | [ 1 , 0 , 1 , 1 , 1 , 0 , 0 , 1 ] [1,0,1,1,1,0,0,1] [1,0,1,1,1,0,0,1] |
1 1 1 | [ 0 , 0 , 1 , 1 , 1 , 0 , 0 , 1 ] [0,0,1,1,1,0,0,1] [0,0,1,1,1,0,0,1] |
2 2 2 | [ 1 , 1 , 1 , 1 , 1 , 0 , 0 , 1 ] [1,1,1,1,1,0,0,1] [1,1,1,1,1,0,0,1] |
3 3 3 | [ 0 , 0 , 0 , 1 , 1 , 0 , 0 , 1 ] [0,0,0,1,1,0,0,1] [0,0,0,1,1,0,0,1] |
4 4 4 | [ 0 , 1 , 1 , 1 , 1 , 0 , 0 , 1 ] [0,1,1,1,1,0,0,1] [0,1,1,1,1,0,0,1] |
5 5 5 | [ 0 , 0 , 0 , 0 , 1 , 0 , 0 , 1 ] [0,0,0,0,1,0,0,1] [0,0,0,0,1,0,0,1] |
6 6 6 | [ 1 , 0 , 1 , 1 , 1 , 1 , 0 , 1 ] [1,0,1,1,1,1,0,1] [1,0,1,1,1,1,0,1] |
7 7 7 | [ 1 , 0 , 0 , 0 , 0 , 1 , 0 , 1 ] [1,0,0,0,0,1,0,1] [1,0,0,0,0,1,0,1] |
8 8 8 | [ 0 , 1 , 0 , 1 , 1 , 1 , 1 , 0 ] [0,1,0,1,1,1,1,0] [0,1,0,1,1,1,1,0] |
【样例 #3】
见选手文件中的 revflip/revflip3.in
与 revflip/revflip3.ans
。
【样例 #4】
见选手文件中的 revflip/revflip4.in
与 revflip/revflip4.ans
。
【数据范围】
对于所有数据保证: 1 ≤ n ≤ 2 × 1 0 6 1\le n\le 2\times 10^6 1≤n≤2×106,且对于任意 1 ≤ i ≤ n 1\le i\le n 1≤i≤n, a i = 0 a_i=0 ai=0 或 1 1 1。
测试点编号 | n ≤ n\le n≤ | 特殊性质 |
---|---|---|
1 ∼ 3 1\sim 3 1∼3 | 1 0 3 10^3 103 | 无 |
4 ∼ 5 4\sim 5 4∼5 | 1 0 5 10^5 105 | 无 |
6 ∼ 7 6 \sim 7 6∼7 | 2 × 1 0 6 2\times 10^6 2×106 | a i = 0 a_i=0 ai=0 |
8 ∼ 10 8\sim 10 8∼10 | 2 × 1 0 6 2\times 10^6 2×106 | 无 |
思路
起初是暴力写的,过不了全部测试。看了题解,也听到很多关于奇偶…,很不理解。别人的代码,看不下去,也看不懂,只是看看思路,朝那个方向,去思考,发现规律。最后算是解决了。
我们先思考第一个变换
假设
起初: 1 2 3 4 …i…n
变换一次: i…4 3 2 1…n
变换两次: i+1 1 2 3 4…i…n可以发现对于1~i,进行了
两次
翻转,位置向后移一.怎样理解呢,如果翻转的数据不变,翻转两次相当于,回到原位不变,而按照题中的翻转,第一次是1 ~ i;第二次多了一个i+1,转到了第一位,以至于翻转两次,向后移一。`当进行n次偏转后, 翻转偶数次k的,向后移k/2;
翻转奇数次k+1的,第k+1也就是i=n,所有数字的翻转。
因此再定义一个数组b,将元素按新位置存放
再看第二次变换,
易知反转偶数次不变,a[n]反转1次,也就是n-=2,所对应下标都是反转奇数次,要改变。所以,在第一个变换之前,现将所有该反转的数字,改变,这样之后不用考虑第二种变化
代码如下
#include<bits/stdc++.h>
using namespace std;
int n,a[2000006],b[2000006];
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
//重点要先进行第二种变换
for(int j=n;j>=1;j-=2)
// j-=2,都是转奇数次,需改变。
{
if(a[j]==1) a[j]=0;
else a[j]=1;
}
//下面是第一种变换
for(int j=1;j<=n;j++)
{
if((n-j+1)&1) //a[j]移动次数是否为奇数
b[n-((n-j+1)/2+j)+1]=a[j];
else
b[(n-j+1)/2+j]=a[j];
}
for(int i=1;i<=n;i++)
cout<<b[i]<<" ";
}