问题描述
DZY有一个序列 a ,一共由 n 个正整数组成,下标为 1 到 n 。我们定义第 i 个数为 ai 。 DZY每次给定一个数对( l,r ) (l≤r) ,他想计算有多少个数对( i,j ),满足 l≤i≤j≤r ,且序列 b=aiai+1⋯aj 有恰好 k 个逆序对。而且,DZY会询问你 q 次噢。
题解:
1.考虑如何计算一个区间中有多少个子区间的逆序对数小于等于 K 。这样做两遍就能算出恰好等于 K 的了。
2.对于 i(1≤i≤n) ,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(); } }