兔子的逆序对
链接:https://ac.nowcoder.com/acm/problem/20861
来源:牛客网
题目描述
兔子最近喜欢上了逆序对。
一个逆序对(i,j) 需要满足 i < j 且 ai > aj
一个逆序对(i,j) 需要满足 i < j 且 ai > aj
兔子觉得只是求一个序列的逆序对个数太没有意思了。
于是兔子想到了一个更有趣的问题!
兔子可以把区间[L,R] 反转,例如序列{1,2,3,4} 反转区间[1,3] 后是{3,2,1,4}。
兔子有m次反转操作,现在兔子想知道每次反转后逆序对个数是奇数还是偶数,兔子喜欢偶数,而讨厌奇数。
请注意,每一次反转操作都会对原序列进行改变。例如序列{1,2,3,4} 第一次操作区间[1,2] 后变成{2,1,3,4} 第二次反转区间[3,4] 后变成 {2,1,4,3}
于是兔子想到了一个更有趣的问题!
兔子可以把区间[L,R] 反转,例如序列{1,2,3,4} 反转区间[1,3] 后是{3,2,1,4}。
兔子有m次反转操作,现在兔子想知道每次反转后逆序对个数是奇数还是偶数,兔子喜欢偶数,而讨厌奇数。
请注意,每一次反转操作都会对原序列进行改变。例如序列{1,2,3,4} 第一次操作区间[1,2] 后变成{2,1,3,4} 第二次反转区间[3,4] 后变成 {2,1,4,3}
输入描述:
第一行一个整数 n,表示序列的大小。
第二行 n 个整数ai表示序列的各个元素。
第三行一个整数m,表示操作个数。
接下来 m 行,每行两个整数 l,r,表示反转的区间。
输出描述:
输出共m行每行一个字符串,表示反转后序列逆序对个数的奇偶性,如果是逆序对个数奇数,输出"dislike"(不含引号),如果是偶数,输出"like"。
输入
4 1 2 3 4 4 1 2 3 4 1 4 2 3
输出
dislike like like dislike
说明
注意:以下的(i,j)指的是位置 i 和位置 j
a={2,1,3,4} 的逆序对是 (1,2) 共1个,1是奇数,所以是dislike
a={2,1,4,3} 的逆序对是 (1,2) (3,4)共2个,2是偶数,所以是like
a={3,4,1,2} 的逆序对是 (1,3) (1,4) (2,3) (2,4)共4个,4是偶数,所以是like
a={3,1,4,2} 的逆序对是 (1,2) (1,4) (3,4) 共3个,3是奇数,所以是dislike
思路
逆序数有个性质,交换两个数的位置,奇排列变成偶排列,偶排列变成奇排列,所以每次交换后只要知道交换了几次即可。开始的逆序数可以通过树状数组求出,也可以通过归并排序算出。
树状数组:
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn=1e5+10; 6 7 8 int tree[maxn],a[maxn],n; 9 int sum(int x) 10 { 11 int s=0; 12 while(x>0) 13 { 14 s+=tree[x]; 15 x-=x&(-x); 16 } 17 return s; 18 } 19 void update(int x,int v) 20 { 21 while(x<=n) 22 { 23 tree[x]+=v; 24 x+=x&(-x); 25 } 26 } 27 int qr() 28 { 29 char c=getchar(); 30 int s=0,flag=1; 31 while(c<'0'||c>'9'){if(c=='-')flag=-1;c=getchar();} 32 while(c>='0'&&c<='9'){s*=10;s+=c-'0';c=getchar();} 33 return s*flag; 34 } 35 signed main() 36 { 37 n=qr(); 38 int s=0; 39 for(int i=1;i<=n;i++) 40 { 41 a[i]=qr(); 42 s+=sum(a[i]); 43 update(1,1); 44 update(a[i],-1); 45 } 46 int m=qr(),flag; 47 if(s%2) 48 flag=1; 49 else 50 flag=-1; 51 for(int i=0;i<m;i++) 52 { 53 int l=qr(),r=qr(); 54 if(((r-l+1)>>1)&1) 55 flag=-flag; 56 if(flag==1) 57 printf("dislike\n"); 58 else 59 printf("like\n"); 60 } 61 return 0; 62 }
归并:
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn=1e5+10; 6 7 int a[maxn],n,sum; 8 int qr() 9 { 10 char c=getchar(); 11 int s=0,flag=1; 12 while(c<'0'||c>'9') 13 { 14 if(c=='-')flag=-1; 15 c=getchar(); 16 } 17 while(c>='0'&&c<='9') 18 { 19 s*=10; 20 s+=c-'0'; 21 c=getchar(); 22 } 23 return s*flag; 24 } 25 int c[maxn]; 26 void Merge(int sl,int sr,int el,int er) 27 { 28 int i=sl,j=el,num=0; 29 while(i<=sr||j<=er) 30 { 31 if(i<=sr&&(a[i]<=a[j]||j>er)) 32 c[num++]=a[i++]; 33 else 34 c[num++]=a[j++],sum+=sr-i+1; 35 } 36 for(int k=0; k<num; k++) 37 a[sl+k]=c[k]; 38 } 39 void MergeSort(int l,int r) 40 { 41 if(l<r) 42 { 43 int mid=(l+r)>>1; 44 MergeSort(l,mid); 45 MergeSort(mid+1,r); 46 Merge(l,mid,mid+1,r); 47 } 48 } 49 signed main() 50 { 51 n=qr(); 52 for(int i=1; i<=n; i++) 53 a[i]=qr(); 54 MergeSort(1,n); 55 int m=qr(),flag; 56 if(sum%2) 57 flag=1; 58 else 59 flag=-1; 60 for(int i=0; i<m; i++) 61 { 62 int l=qr(),r=qr(); 63 if(((r-l+1)>>1)&1) 64 flag=-flag; 65 if(flag==1) 66 printf("dislike\n"); 67 else 68 printf("like\n"); 69 } 70 return 0; 71 }