专栏文章
题解:P1966 [NOIP2013 提高组] 火柴排队
P1966题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @miqin84c
- 此快照首次捕获于
- 2025/12/04 05:25 3 个月前
- 此快照最后确认于
- 2025/12/04 05:25 3 个月前
题目传送门
思路
首先观察要最小化的式子 ,由于 ,所以有 。
由于 和 无论如何排列火柴都不会改变,所以问题转化为最大化 。可以证明,把两个序列排序后,对每个 ,将第 小的 元素与第 小的 元素配对,这样得到的 是最大的。
然后考虑如何计算答案,可以发现在第 列交换和在第 列中交换是等价的,所以只考虑对一列进行交换。
首先排序,然后计算出两个数组 和 , 表示第 列中第 个元素在第 列中是第 大的, 表示第 列中第 个元素在第 列中是第 大的。由此,问题便转化为至少需要交换多少个相邻元素,使得 序列变成 序列。
这里由于两个数组都是一个排列,所以可以先做一个映射,然后就用归并排序求逆序对就可以了。
代码
CPP#include<bits/stdc++.h>
using namespace std;
const int N=1e5+1;
const int mod=1e8-3;
int a[N],b[N],c[N],d[N],r[N];
long long ans=0;
map<int,int> ai;
map<int,int> bi;
map<int,int> m;
void read(int &x){
int f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
x*=f;
}
void msort(int left,int right){//归并排序求逆序对
if(left==right)return;
int mid=(left+right)/2;
msort(left,mid);
msort(mid+1,right);
int i=left,j=mid+1,k=left;
while(i<=mid&&j<=right){
if(a[i]<=a[j]){
r[k]=a[i];
k++;
i++;
}else{
r[k]=a[j];
k++;
j++;
ans=(ans+mid-i+1)%mod;//记得取模
}
}
while(i<=mid){
r[k]=a[i];
k++;
i++;
}
while(j<=right){
r[k]=a[j];
k++;
j++;
}
for(int i=left;i<=right;i++) a[i]=r[i];
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
read(a[i]);
c[i]=a[i];//记录c[i]
ai[a[i]]=i;
}
for(int i=1;i<=n;i++){
read(b[i]);
d[i]=b[i];//记录d[i]
bi[b[i]]=i;
}
sort(c+1,c+1+n);
sort(d+1,d+1+n);
for(int i=1;i<=n;i++){
b[bi[d[i]]]=i;
a[ai[c[i]]]=i;
}
for(int i=1;i<=n;i++)m[b[i]]=i;//映射
for(int i=1;i<=n;i++)a[i]=m[a[i]];
msort(1,n);//求逆序对
printf("%lld",ans%mod);
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...