Date:2022.01.17
题意:
n
∗
m
n*m
n∗m个座,
n
∗
m
n*m
n∗m个人。每个人都有近视度,近视度小的坐的座位下标靠前,因此相对位置固定。每个人要找到他所在的行,并进入所在的列,在此过程中,定义这个人的“不方便程度”为他在这一行往里走的过程中,经过了多少个比他下标小的人。求总的不方便度最小是多少。
D1:
n
=
1
n=1
n=1,其它同D2。
D2:
思路①:D1只有一行,贪心【贪心见下】放进去,暴力(不如练练BIT板子)。
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int N = 310;
typedef long long LL;
LL t,n,m,k;
LL a[N],tr[N];
struct node
{
LL zhi,idx;
}s[N];
bool cmp(node a,node b)
{
if(a.zhi==b.zhi) return a.idx>b.idx;
return a.zhi<b.zhi;
}
LL lowbit(LL x)
{
return x&-x;
}
void add(LL x,LL c)
{
for(int i=x;i<=m;i+=lowbit(i)) tr[i]+=c;
}
LL sum(LL x)
{
LL res=0;
for(int i=x;i;i-=lowbit(i)) res+=tr[i];
return res;
}
int main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>t;
while(t--)
{
memset(tr,0,sizeof tr);
cin>>n>>m;
for(int i=1;i<=m;i++) {cin>>s[i].zhi;s[i].idx=i;}
sort(s+1,s+1+m,cmp);
LL res=0;
for(int i=1;i<=m;i++)
{
res+=sum(s[i].idx);
add(s[i].idx,1);
}
cout<<res<<endl;
}
return 0;
}
思路②:D2有
n
∗
m
n*m
n∗m人,我们先来考虑如果我们得出第
1
1
1 ~
n
∗
m
n*m
n∗m个人应该在哪个座位上,我们能不能求出来总的正序对个数?
n
∈
300
,
m
∈
300
n\in300,m\in300
n∈300,m∈300,
O
(
n
3
)
O(n^3)
O(n3)枚举每个元素之前有多少比它小的,再累加即可求得。
因此考虑如何找到每个人该坐在哪个位置,不同于D1,D2可能存在相同近视度的人分别处于一行尾部和另一行头部的形式,模拟放入。我开了一个
q
u
e
u
e
queue
queue类型的数组,
q
u
e
u
e
[
i
]
queue[i]
queue[i]中含所有近视度为i的人的下标,近视度本身可能很大,我们直接开
q
u
e
u
e
[
i
]
queue[i]
queue[i]可能会开到
1
0
9
10^9
109这不现实。我们只需要用到近视度的相对关系,因此离散化,
q
u
e
u
e
queue
queue最大也只会开
n
∗
m
n*m
n∗m项,所有
q
u
e
u
e
queue
queue中所有项不会超过人的上限
n
∗
m
n*m
n∗m,因此全遍历完所有
q
u
e
u
e
queue
queue时间是允许的。
剩下就模拟+贪心,不难发现值相同情况下能先往里坐就先往里坐,这样能保证后进来的、且下标较大的元素相对位置靠前,也就不会经过下标比他小的元素。此外,放人的顺序应按近视度由小到大放,放完一个近视度的所有人才能放更大近视度的人。
外
q
u
e
u
e
queue
queue清空无法
c
l
e
a
r
(
)
clear()
clear(),因此每次暴力弹出所有元素。
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int N = 310;
typedef long long LL;
LL t,n,m,k;
LL c[N][N];
LL a[N*N],b[N*N];
queue<LL>q[N*N];
int main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>t;
while(t--)
{
for(int i=1;i<=300*300;i++)
while (!q[i].empty()) q[i].pop();
LL maxx=0;
cin>>n>>m;
for(int i=0;i<n*m;i++) {cin>>a[i];b[i]=a[i];}
sort(b,b+n*m);
LL x=unique(b,b+n*m)-b;
for(int i=0;i<n*m;i++)
{
a[i]=lower_bound(b,b+x,a[i])-b+1;
maxx=max(maxx,a[i]);
q[a[i]].push(i+1);
}
LL row=0,zhi=1;
LL sy=m,dq=q[1].size();
for(int i=1;i<=n&&zhi<=maxx;)
{
if(dq>=sy)
{
dq-=sy;
for(int j=m;j>=m-sy+1;j--) {c[i][j]=q[zhi].front();q[zhi].pop();}
sy=0;
}
else if(dq<sy)
{
for(int j=m-sy+dq;j>=m-sy+1;j--) {c[i][j]=q[zhi].front();q[zhi].pop();}
sy-=dq;
dq=0;
}
//cout<<dq<<' '<<sy<<endl;
if(sy==0) {i++;sy=m;}
if(dq==0) {zhi++;dq=q[zhi].size();}
}
LL ans=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
for(int k=1;k<j;k++)
if(c[i][k]<c[i][j]) ans++;
}
}
cout<<ans<<endl;
}
return 0;
}