[优先队列]HDOJ5289 Assignment

题意:有多少个区间,区间内最大的数减去最小的数差小于k

 

对每个数它所在的区间,可以只往前找(类似dp的无后效性) 比如对位置3的数,可以往前找的区间是[3, 3], [2, 3], [1, 3], [0, 3]这样

这样 遍历a[i] 对每个a[i]往前 就可以得到所有的区间

比如案例

10 5

0 3 4 5 2 1 6 7 8 9

(最小值,最大值)的形式

 

每个数增加一个(自己,自己)

 

一旦不满足条件了就不必再进行下去

那么很容易想到这是一个类似队列的情况

 

对于这个案例 跑一下队列就是

 

 (把队中元素的个数加起来就是结果)

 

 

那么问题就转化成了怎么知道队列中存在一个数是要弹出的(也就是上述案例6的时候,怎么知道1在队列中)

我先用优先队列处理了一下每个数前面需要弹出的数的位置的最大值

再用队列模拟上述过程即可

 

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 #define lson l, m
 5 #define rson m+1, r
 6 const int N=1e5+5;
 7 const LL mod=1e9+7;
 8 typedef pair<int, int> PI;
 9 PI a[N];
10 int minn[N], maxn[N];
11 void out(priority_queue<PI, vector<PI>, greater<PI> > q)
12 {
13     while(!q.empty())
14     {
15         printf("(%d %d)  ", q.top().first, q.top().second);
16         q.pop();
17     }
18     puts("");
19 }
20 
21 int main()
22 {
23 //    freopen("1002.in", "r", stdin);
24 //    freopen("out.txt", "w", stdout);
25     int t;
26     scanf("%d", &t);
27     while(t--)
28     {
29         int n, k;
30         scanf("%d%d", &n, &k);
31         for(int i=0;i<n;i++)
32         {
33             int x;
34             scanf("%d", &x);
35             a[i]=make_pair(x, i);
36         }
37         memset(minn, -1, sizeof(minn));
38         memset(maxn, -1, sizeof(maxn));
39         priority_queue<PI, vector<PI>, greater<PI> > q1;
40         while(!q1.empty())
41             q1.pop();
42         q1.push(a[0]);
43         for(int i=1;i<n;i++)
44         {
45             while(q1.size()>0 && a[i].first-q1.top().first>=k)
46             {
47                 minn[i]=max(q1.top().second, minn[i]);
48                 q1.pop();
49             }
50             q1.push(a[i]);
51 //            out(q1);
52         }
53         priority_queue<PI, vector<PI>, less<PI> > q2;
54         while(!q2.empty())
55             q2.pop();
56         q2.push(a[0]);
57         for(int i=1;i<n;i++)
58         {
59             while(q2.size()>0 && q2.top().first-a[i].first>=k)
60             {
61                 maxn[i]=max(q2.top().second, maxn[i]);
62                 q2.pop();
63             }
64             q2.push(a[i]);
65         }
66 //        for(int i=0;i<n;i++)
67 //            printf("%d %d\n", minn[i], maxn[i]);
68 
69         LL ans=0;
70         queue<int> Q;
71         while(!Q.empty())
72             Q.pop();
73         int cur=0;
74         for(int i=0;i<n;i++)
75         {
76             if(minn[i]<cur)
77                 minn[i]=-1;
78             if(maxn[i]<cur)
79                 maxn[i]=-1;
80             while(!Q.empty() && (maxn[i]!=-1 || minn[i]!=-1))
81             {
82                 if(Q.front()==maxn[i])
83                     maxn[i]=-1;
84                 if(Q.front()==minn[i])
85                     minn[i]=-1;
86                 cur=Q.front();
87                 Q.pop();
88             }
89             Q.push(a[i].second);
90             ans+=Q.size();
91         }
92         printf("%I64d\n", ans);
93     }
94     return 0;
95 }
HDOJ 5289

 

转载于:https://www.cnblogs.com/Empress/p/4666625.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值