「KDOI-06-J」翻转与反转
洛谷:https://www.luogu.com.cn/problem/P9741?contestId=125612
输入 #1
3
1 1 1
输出 #1
0 0 1
输入 #2
8
1 0 1 1 1 0 0 1
输出 #2
0 1 0 1 1 1 1 0
思路1:
因为数据在2e6如果进行暴力的话会超时,所以就需要找规律,也就变成了一个思维问题。
对于第i个数,我们很容易知道需要对它操作n-i+1次
对于第1个变换(前i个数交换次序),可以发现,第i位在进行第一次操作时向前移动了i-1位,而第二次操作时向后移动i位,第三次又向前移动了i-1位,那么就可以推出来,操作两次共往后移动1位,如果有剩余(即需要操作奇数次),那么就再往前移动了i-1位就可以了。
对于第2个变换(数值翻转),操作为奇数次时,这一位上会发生变换,反之操作偶数次时,这一位上不会变换。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 2e5+5
int a[2000001];
int b[2000001];
void solve(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];//存储原来的数据
}
for(int i=1;i<=n;i++){
int p=n-i+1;//需要操作的次数
int ans=0;//需要变换的位置(需要向前/后移多少位)
if(p%2==0){
ans=p/2;
b[ans+i]=a[i];
}
else{
p--;
ans=p/2-i+1;//ans先向后移动p/2位,再向前移动i-1位
if(a[i]==0){
b[ans+i]=1;
}
else
b[ans+i]=0;
}
}
for(int i=1;i<=n;i++){
cout<<b[i]<<" ";//存储变换之后的数据
}
}
int main(){
int t=1;
while(t--){
solve();
}
return 0;
}
思路2:
不管进行到第几次操作(假设为i)那么i这个位置上的数现在必定排列在第一位,那么在第i+1次的时候原来i位置上的数就改变到i+1的位置上了
n-2 n-3
n-1 n-2
n n-1
(像这样排列一样)
那么变换到最后一定为n n-2 n-4 … 1 … n-3 n-1 中间一定为1
并且对于前半段(即1之前的元素)一定操作了奇数次,所以一定需要进行取反的,对于1即1后面的数就需要进行讨论了:
当n为偶数时,1的前一位一定会是2,那么后半段开始的元素就需要从3开始,并且1这一位一共操作了n-i+1次即n次,是偶数次,所以不需要进行变换。
当n为奇数时,1的前一位一定会是3,那么后半段开始的元素就需要从2开始,并且1这一位一共操作了n-i+1次即n次,是奇数次,所以需要进行变换。
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 2e5+5
int a[2000001];
void solve(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=n;i>1;i-=2){
cout<<!a[i]<<" ";
}
if(n%2==0){
cout<<a[1]<<" ";
for(int i=3;i<=n-1;i+=2){
cout<<a[i]<<" ";
}
}
else{
cout<<!a[1]<<" ";
for(int i=2;i<=n-1;i+=2){
cout<<a[i]<<" ";
}
}
}
int main(){
int t=1;
while(t--){
solve();
}
return 0;
}