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 }
那么,AC代码在此
原文地址:https://www.cnblogs.com/huyufeifei/p/8707891.html