P1966 火柴排队
这道题需要小小的思考一波
(然而我思考了两节课)
好,我们先得出一个结论:a中第k大的与b中第k大的一定要排在一起,才能保证最小。
然后发现:挪a,b其实没有区别,故我们固定a,挪b。
然后我们就思考:只能挪相邻的,那么就是求逆序对数啊!
那么我们把这两个固定到结构体里,按a排序,求b的逆序对。
交上去,自信WA,10分。。。
让我们看一组样例:
4
4 1 2 3
3 1 2 4
显然要5下,但我的程序无情的输出了一个1
那么我们再思考:
逆序对的目的是把这些东西挪成1,2,3,4,5,6,7......
那么我们给这些东西的目标位置顺序标号1,2,3,4,5,6,7......,记为aim,分别扔到现在位置上。
这些东西现在的位置记为1,2,3,4,5,6,7......,记为num
那么我们把这些东西从num挪到aim,等效于从aim挪到num
由于num是有序的,我们求aim的逆序对就OK了!
本题并不用离散化(李三花)
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define lowbit(a) (a&(-a)) 5 using namespace std; 6 const int N = 100010; 7 const int mo= 99999997; 8 int n,/*x[N],*/tree[N]; 9 struct March 10 { 11 int sum,num,aim; 12 }a[N],b[N]; 13 void add(int x,int v) 14 { 15 for(int i=x;i<=n;i+=lowbit(i)) tree[i]+=v; 16 return; 17 } 18 int getsum(int x) 19 { 20 int ans=0; 21 for(int i=x;i>0;i-=lowbit(i)) ans+=tree[i]; 22 return ans; 23 } 24 bool cmp1(March f,March d) 25 { 26 return f.sum<d.sum; 27 } 28 bool cmp2(March f,March d) 29 { 30 return f.num<d.num; 31 } 32 33 int main() 34 { 35 scanf("%d",&n); 36 for(int i=1;i<=n;i++) 37 { 38 scanf("%d",&a[i].sum); 39 a[i].num=i; 40 } 41 for(int i=1;i<=n;i++) 42 { 43 scanf("%d",&b[i].sum); 44 b[i].num=i; 45 //x[i]=b[i].sum; 46 } 47 /* 48 sort(x+1,x+n+1); 49 int k=0; 50 for(int i=1;i<=n;i++) if(x[i]!=x[i-1]) x[++k]=x[i]; 51 */ 52 sort(a+1,a+n+1,cmp1); 53 sort(b+1,b+n+1,cmp1); 54 for(int i=1;i<=n;i++) b[i].aim=a[i].num; 55 sort(b+1,b+n+1,cmp2); 56 int ans=0; 57 for(int i=1;i<=n;i++) 58 { 59 ans+=(i-1-getsum(b[i].aim)); 60 ans%=mo; 61 add(b[i].aim,1); 62 } 63 64 printf("%d",ans); 65 66 return 0; 67 }