标签:
题目链接:
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1087 Accepted Submission(s): 323
有一个序列,然后你可以删除一个长度为mm的连续子序列. 问如何删除才能使逆序对最少.
思路:
也是套路,逆序对可以用树状数组求得,连续的可以使用滑动窗口,跟尺取法差不多啦;开了两个树状数组一个记录左边界之前的数,一个记录右边界后面的数,然后更新逆序对的数目,取最小就好了;
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=1e5+10;
int sum1[maxn],sum2[maxn],n,m,a[maxn];
int lowbit(int x){return x&(-x);}
inline void update1(int x,int num)
{
while(x<=n)
{
sum1[x]+=num;
x+=lowbit(x);
}
}
inline int query1(int x)
{
int s=0;
while(x)
{
s+=sum1[x];
x-=lowbit(x);
}
return s;
}
inline void update2(int x,int num)
{
while(x<=n)
{
sum2[x]+=num;
x+=lowbit(x);
}
}
inline int query2(int x)
{
int s=0;
while(x)
{
s+=sum2[x];
x-=lowbit(x);
}
return s;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=0;i<=n;i++)sum1[i]=sum2[i]=0;
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
LL su=0;
for(int i=n;i>0;i--)
{
su=su+query2(a[i]-1);
update2(a[i],1);
}
LL ans=su,temp=su;int l,r=1;
for(l=1;l<=n-m+1;l++)
{
while(r-l<m&&r<=n)
{
update2(a[r],-1);
temp=temp-query2(a[r]-1);
temp=temp-(l-1-query1(a[r]));
r++;
}
ans=min(ans,temp);
temp=temp+(l-1-query1(a[l]));
temp=temp+query2(a[l]-1);
update1(a[l],1);
}
printf("%lld\n",ans);
}
return 0;
}
标签:
原文地址:http://www.cnblogs.com/zhangchengc919/p/5922283.html