【洛谷P1966】火柴排队

火柴排队

题目链接

(aibi)^2=∑ai^2-2*∑ai*bi+∑bi^2

显然∑ai^2+∑bi^2是不变的,我们要让

2*∑ai*bi最大,才能使原式最小

然后我们一眼就可以看出来,

当第i大的ai与第i大的bi一一对应时,∑ai*bi最大

反正我不会证

知道了对应关系后,于是就成了求逆序对的个数了

可以用归并排序或树状数组

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 using namespace std;
 6 #define N 1000010
 7 #define mod 99999997
 8 int n,a[N],ans;
 9 struct HC{
10     int pos,val;
11 } A[N],B[N];
12 inline int read(){
13     int x=0; char c=getchar();
14     while(c<'0'||c>'9') c=getchar();
15     while('0'<=c&&c<='9') { x=(x<<3)+(x<<1)+c-'0'; c=getchar(); }
16     return x;
17 }
18 inline bool cmp(HC a,HC b){
19     return a.val<b.val;
20 }
21 int f[N];
22 void msort(int l,int r){
23     if(l>=r) return;
24     int mid=(l+r)>>1;
25     msort(l,mid); msort(mid+1,r);
26     int i=l,j=mid+1,k=1;
27     while(i<=mid&&j<=r){
28         if(a[i]<=a[j]){
29             f[k]=a[i];
30             i++; k++;
31         }
32         else{
33             f[k]=a[j];
34             ans+=mid-i+1;
35             if(ans>mod) ans-=mod;
36             j++; k++;
37         }
38     }
39     while(i<=mid){ f[k]=a[i]; i++; k++; }
40     while(j<=r) { f[k]=a[j]; j++; k++; }
41     for(int i=1;i<=r-l+1;i++)
42      a[l+i-1]=f[i];
43 }
44 int main()
45 {
46     scanf("%d",&n);
47     for(int i=1;i<=n;i++){
48         A[i].val=read();
49         A[i].pos=i;
50     }
51     for(int i=1;i<=n;i++){
52         B[i].val=read();
53         B[i].pos=i;
54     }
55     sort(A+1,A+1+n,cmp);
56     sort(B+1,B+1+n,cmp);
57     for(int i=1;i<=n;i++)
58      a[B[i].pos]=A[i].pos;
59     msort(1,n);
60     printf("%d\n",ans%mod);
61     return 0;
62 }

 

posted @ 2018-07-24 14:03  yjk  阅读(124)  评论(0编辑  收藏  举报