hdu 5196 DZY Loves Inversions && BestCoder Round #35

来源:互联网 发布:手机淘宝链接生成器 编辑:程序博客网 时间:2024/05/22 10:38

问题描述
DZY有一个序列a,一共由n个正整数组成,下标为1n。我们定义第i个数为ai。DZY每次给定一个数对(l,r)(lr),他想计算有多少个数对(i,j),满足lijr,且序列 b=aiai+1aj 有恰好k个逆序对。而且,DZY会询问你q次噢。

题解:

1.考虑如何计算一个区间中有多少个子区间的逆序对数小于等于K。这样做两遍就能算出恰好等于K的了。
2.对于i(1in),fi表示[i,fi]逆序对数小于等于K,且fi的值最大。显然fi单调不降,我们可
以通过用两个指针扫一遍,利用树状数组计算出f数组。
3.因为ai很大,但是只有1e5个,所以可以进行压缩映射成至多1 -- 1e5,才可以用树状数组维护逆序对数
4.询问l,r时,可以二分找到最大的f[i] <= r,维护一个前缀和
s = (f[l] - l + 1) + .... + (f[l + i] - l - i + 1)表示这些区间所能组成的最大子区间数
5.对于[i + 1,r],f[i + 1]肯定大于r,所以对于区间[i + 1,r],[i + 2,r]....[r,r],维护另一个前缀和
s1 = (r - i - 1 + 1) + ....... + (r - r + 1)表示这些区间所能组成的最大子区间数
总结:
1.看了bestcoder的前两点提醒才想到的,感觉又是一个运用前缀和和单调性思想的题目
2.debug代码的时候还算满意,没有死扣瞎提交,以后坚持,首先争取不犯设计上的错误,然后就要平静的查错
#include<iostream>#include<cstring>#include<cstdio>#include<algorithm>using namespace std;typedef long long LL;#define MAXN 100005#define lowbit(i) (i & -i)int num[MAXN],bit[MAXN],n,q;LL fk1[MAXN],fk2[MAXN],s1[MAXN],s2[MAXN],k;struct Node{    int v,id;    bool operator < (const Node & c)const{        return v < c.v;    }}node[MAXN];int sum(int i){    int total = 0;    for(;i;i -= lowbit(i))        total += bit[i];    return total;}void modify(int i,int key){    for(;i <= n;i += lowbit(i))        bit[i] += key;}void findf(LL k,LL * s,LL * ss){    LL cur = 0;    memset(bit,0,sizeof(bit));    for(int i = 1,j = 0;i <= n;i++)    {        while(j <= n && cur <= k)        {            if(++j > n)break;            cur += (j - i) - sum(num[j]);            modify(num[j],1);        }        cur -= sum(num[i] - 1);        modify(num[i],-1);        s[i] = j - 1;        ss[i] = ss[i - 1] + j - i;    }}LL query(int l,int r){    int ind = upper_bound(fk1 + l,fk1 + r + 1,r) - fk1 - 1;    LL cur = r - ind;    LL ans1 = (cur + 1) * cur / 2 + s1[ind] - s1[l - 1];    if(!k)return ans1;    ind = upper_bound(fk2 + l,fk2 + r + 1,r) - fk2 - 1;    cur = r - ind;    LL ans2 = (cur + 1) * cur / 2 + s2[ind] - s2[l - 1];    return ans1 - ans2;}void solve(){    findf(k,fk1,s1);    if(k)findf(k - 1,fk2,s2);    int l,r;    for(int i = 0;i < q;i++)    {        scanf("%d%d",&l,&r);        LL ans = query(l,r);        printf("%I64d\n",ans);    }}int main(){    while(~scanf("%d%d%I64d",&n,&q,&k))    {        for(int i = 1;i <= n;i++)        {            scanf("%d",&num[i]);            node[i].v = num[i];            node[i].id = i;        }        sort(node + 1,node + n + 1);        num[node[1].id] = 1;        for(int i = 2;i <= n;i++)            if(node[i].v == node[i - 1].v)                num[node[i].id] = num[node[i - 1].id];            else                num[node[i].id] = num[node[i - 1].id] + 1;        solve();    }}


0 0