hdu5196 DZY Loves Inversions 思路,计数
2015-10-06 14:45
337 查看
题意:一个数列,给出一些区间,计算这个区间有多少子区间逆序对数为k。
分析:直接计算k不好算,把问题转化为<=k的子区间数减去<k的子区间数。首先由两个指针可以求出每一个点的满足<=k或<k的最右边界。得到r1和r2数组。
最后所求即为sum(min(r1i,r)-l+1) (i>=l&&i<=r),r数组单调递增,二分即可。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<ostream>
#include<istream>
#include<algorithm>
#include<queue>
#include<string>
#include<cmath>
#include<set>
#include<map>
#include<stack>
#include<vector>
#define fi first
#define se second
#define ll long long
#define pii pair<int,int>
#define inf (1<<30)
#define eps 1e-8
#define pb push_back
#define debug puts("=====")
using namespace std;
const int maxn=100005;
int n,q;
ll k;
int l,r;
int d[maxn];
int dis[maxn];
int r1[maxn],r2[maxn];
ll s1[maxn],s2[maxn];
int tree[maxn];
int lowbit(int x)
{
return x&-x;
}
int Sum(int a)
{
int sum=0;
while(a>0) {
sum+=tree[a];
a-=lowbit(a);
}
return sum;
}
void update(int x,int c)
{
while(x<=n) {
tree[x]+=c;
x+=lowbit(x);
}
}
void pre()
{
memset(tree,0,sizeof(tree));
int i=1,j=0;
ll sum=0;
while(i<=n) {
while(sum<=k && j<=n) {
j++;
if(j==n+1) break;
sum+=Sum(n)-Sum(d[j]);
update(d[j],1);
}
r1[i]=j-1;
update(d[i],-1);
sum-=Sum(d[i]-1);
i++;
}
memset(tree,0,sizeof(tree));
i=1,j=0,sum=0;
while(i<=n) {
while(sum<=k-1 && j<=n) {
j++;
if(j==n+1) break;
sum+=Sum(n)-Sum(d[j]);
update(d[j],1);
}
r2[i]=j-1;
update(d[i],-1);
sum-=Sum(d[i]-1);
i++;
}
s1[0]=s2[0]=0;
for(int i=1;i<=n;i++) {
s1[i]=s1[i-1]+r1[i];
s2[i]=s2[i-1]+r2[i];
}
}
int main()
{
while(~scanf("%d%d%I64d",&n,&q,&k)) {
for(int i=1;i<=n;i++) {
scanf("%d",&d[i]);
dis[i-1]=d[i];
}
sort(dis,dis+n);
int tot=unique(dis,dis+n)-dis;
for(int i=1;i<=n;i++) {
d[i]=lower_bound(dis,dis+tot,d[i])-dis+1;
}
pre();
ll ans;
while(q--) {
ans=0;
scanf("%d%d",&l,&r);
int kk=upper_bound(r1+l,r1+r+1,r)-r1;
kk--;
ans+=s1[kk]-s1[l-1];
ans+=(ll)(r-kk)*r;
if(k==0) {
ans+=(ll)(r-l+1)*(2-l-r)/2;
printf("%I64d\n",ans);
continue;
}
kk=upper_bound(r2+l,r2+r+1,r)-r2;
kk--;
ans-=s2[kk]-s2[l-1];
ans-=(ll)(r-kk)*r;
printf("%I64d\n",ans);
}
}
return 0;
}
分析:直接计算k不好算,把问题转化为<=k的子区间数减去<k的子区间数。首先由两个指针可以求出每一个点的满足<=k或<k的最右边界。得到r1和r2数组。
最后所求即为sum(min(r1i,r)-l+1) (i>=l&&i<=r),r数组单调递增,二分即可。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<ostream>
#include<istream>
#include<algorithm>
#include<queue>
#include<string>
#include<cmath>
#include<set>
#include<map>
#include<stack>
#include<vector>
#define fi first
#define se second
#define ll long long
#define pii pair<int,int>
#define inf (1<<30)
#define eps 1e-8
#define pb push_back
#define debug puts("=====")
using namespace std;
const int maxn=100005;
int n,q;
ll k;
int l,r;
int d[maxn];
int dis[maxn];
int r1[maxn],r2[maxn];
ll s1[maxn],s2[maxn];
int tree[maxn];
int lowbit(int x)
{
return x&-x;
}
int Sum(int a)
{
int sum=0;
while(a>0) {
sum+=tree[a];
a-=lowbit(a);
}
return sum;
}
void update(int x,int c)
{
while(x<=n) {
tree[x]+=c;
x+=lowbit(x);
}
}
void pre()
{
memset(tree,0,sizeof(tree));
int i=1,j=0;
ll sum=0;
while(i<=n) {
while(sum<=k && j<=n) {
j++;
if(j==n+1) break;
sum+=Sum(n)-Sum(d[j]);
update(d[j],1);
}
r1[i]=j-1;
update(d[i],-1);
sum-=Sum(d[i]-1);
i++;
}
memset(tree,0,sizeof(tree));
i=1,j=0,sum=0;
while(i<=n) {
while(sum<=k-1 && j<=n) {
j++;
if(j==n+1) break;
sum+=Sum(n)-Sum(d[j]);
update(d[j],1);
}
r2[i]=j-1;
update(d[i],-1);
sum-=Sum(d[i]-1);
i++;
}
s1[0]=s2[0]=0;
for(int i=1;i<=n;i++) {
s1[i]=s1[i-1]+r1[i];
s2[i]=s2[i-1]+r2[i];
}
}
int main()
{
while(~scanf("%d%d%I64d",&n,&q,&k)) {
for(int i=1;i<=n;i++) {
scanf("%d",&d[i]);
dis[i-1]=d[i];
}
sort(dis,dis+n);
int tot=unique(dis,dis+n)-dis;
for(int i=1;i<=n;i++) {
d[i]=lower_bound(dis,dis+tot,d[i])-dis+1;
}
pre();
ll ans;
while(q--) {
ans=0;
scanf("%d%d",&l,&r);
int kk=upper_bound(r1+l,r1+r+1,r)-r1;
kk--;
ans+=s1[kk]-s1[l-1];
ans+=(ll)(r-kk)*r;
if(k==0) {
ans+=(ll)(r-l+1)*(2-l-r)/2;
printf("%I64d\n",ans);
continue;
}
kk=upper_bound(r2+l,r2+r+1,r)-r2;
kk--;
ans-=s2[kk]-s2[l-1];
ans-=(ll)(r-kk)*r;
printf("%I64d\n",ans);
}
}
return 0;
}
相关文章推荐
- 图文并茂简介如何查询文章是否被SCI收录以及获取SCI索引号
- [html] 回到页首
- 算法-高位优先的字符串排序
- python基础8之爬虫
- SQL server 约束
- 在数组中取一个位置,让这个位置之前的树的和与之后的和的差绝对值最小
- 在Android中用ndk层egl/opengl es显示java层打开的图像
- poj 1753 Flip Game 【高斯消元 + 状压枚举自由变元】
- VBA 第14课 自动生成年历
- LeetCode H-Index
- 要毕业季
- 继续来码~python对象简介~
- HTML 字符实体与随笔练习
- Java中的并发工具集
- jQuery源码分析之$.inArray()函数
- UVa 10256 (计算几何基础摸板)
- eclipse常用快捷键
- Codeforces Round #260 (Div. 1) --B. A Lot of Games (Trie)
- MySQL执行报错:ERROR 1148 (42000): The used command is not allowed with this MySQL version
- perl数据结构输出 Data::Dumper