P9741 「KDOI-06-J」翻转与反转题解

· · 题解

题目简述

给定一个只有 0 和 1 构成,长度为 n 的序列 a,对这个序列 a 进行 n 次操作,第 i 次操作把 1\sim i 的子序列翻转,再把翻转后的 1\sim i 每位数取反,求最终的序列 a。

思路

对于这种和题目,暴力肯定会 TLE,可以先打表找找规律,我用 !x 表示取反 x,如下:

结果:$!a_1$。 $n=2$, 结果:$!a_2,a_1$。 $n=3$, 结果:$!a_3,!a_1,a_2$。 $n=4$, 结果:$!a_4,!a_2,a_1,a_3$。 $n=5$, 结果:$!a_5,!a_3,!a_1,a_2,a_4$。 可以发现,如果 $n$ 为奇数,前 $\lceil \dfrac{n}{2} \rceil$ 个数都被取反,且下标从 $n$ 开始,逐次减 $2$ 到 $1$。后 $\lfloor \dfrac{n}{2} \rfloor$ 个数没有被取反,下标从 $2$ 开始,逐次加 $2$ 到 $n-1$。 如果 $n$ 为偶数,前 $\dfrac{n}{2}$ 个数都被取反,且下标从 $n$ 开始,逐次减 $2$ 到 $2$。后 $\dfrac{n}{2}$ 个数没有被取反,下标从 $1$ 开始,逐次加 $2$ 到 $n-1$。 我们现在可以先算出前 $\lceil \dfrac{n}{2} \rceil$ 个数,在算出后 $\lfloor \dfrac{n}{2} \rfloor$ 个数,时间复杂度为 $O(n)$,不会 TLE。 ## Code ``` #include<bits/stdc++.h> using namespace std; int n,a[2000010]; int main(){ cin>>n; for(int i=1;i<=n;i++) cin>>a[i];//输入 if(n&1){//如果 n为奇数 for(int i=n;i>=1;i-=2){// 从 n开始,到 1 cout<<(a[i]^1)<<' ';// 异或 1等于取反 } for(int i=2;i<n;i+=2){// 从 2开始,到 n-1 cout<<a[i]<<' '; } }else{//否则为偶数 for(int i=n;i>=2;i-=2){// 从 n开始,到 2 cout<<(a[i]^1)<<' '; } for(int i=1;i<n;i+=2){// 从 1开始,到 n-1 cout<<a[i]<<' '; } } return 0; } ```