Problem I. Wiki with Special Poker Cards
Input file: standard input Time limit: 1 second
Output file: standard output Memory limit: 256 megabytes
"耶,我赢了! "教室里传来一阵阵快乐的笑声。这是在干什么呢?原来他们在举行"扑克牌游戏"呢。而
作为本次游戏的组织者, Wiki也同时制定了游戏的规则,规则如下:
游戏现场一共有n张扑克牌,但是有别于传统的扑克牌,本次游戏所采用的扑克牌,其牌面大小都在整数
区间[1; 106]之内。把这n张扑克牌按照从左往右的顺序平放在桌子上,牌面大小依次为a1; a2; :::; an。
现在请游戏参与者从这n张扑克牌中挑出连续的m张扑克,满足这m张扑克中牌面最大的那张ai与最小的
那张aj(1 <= i; j <= n)的差值小于等于r,且这m张扑克的牌面加起来的和大于等于s。
游戏期间,同学们依次上场,每人游戏结束以后, Wiki会记录每位同学拿到的牌数m,且每位游戏参与
者拿到的这m张牌必须符合上述游戏规则,不符合规则则记录为0!
为了保证游戏的公平性,每人游戏结束以后, Wiki会把这n张牌重新摆放到初始位置,保证每位参与游
戏的同学都能在相同的条件下进行游戏。最后,谁拿到的牌数最多(也就是m),谁就赢得游戏胜利。
Input
第一行输入三个正整数n; r; s(1 <= n <= 105; 0 <= r; s <= 106)
接下来输入n个正整数ai(1 <= i <= n),两数之间用空格隔开,表示n张牌牌面的大小(0 <= ai <= 106)
Output
在满足游戏规则的前提下,输出m的最大值
Samples
standard input | standard output |
5 0 5 1 1 1 1 1 |
5 |
5 3 10 1 2 3 4 5 |
4 |
思路:
利用两个单调队列,一个维护以i为终止节点的单调不减队列记录区间最小值,另一个维护以i为终止节点的单调不增队列记录区间最大值
用一个指针记录满足最大值最小值的最小下标,如果该区间满足前缀和要求,则用该区间去更新答案,否则不更新
1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 #include <deque> 5 6 7 using namespace std ; 8 9 const int N = 100010 ; 10 deque<int> miv,mav ; 11 12 int a[N],sum[N] ; 13 int n,r,s ; 14 15 16 int main(){ 17 cin >> n >> r >> s ; 18 19 for(int i=1;i<=n;i++){ 20 cin >> a[i] ; 21 sum[i] = sum[i-1] + a[i] ; 22 } 23 24 int last = 0, ans = 0 ; 25 for(int i=1;i<=n;i++){ 26 while(!mav.empty() && a[mav.back()] < a[i]) mav.pop_back() ; 27 while(!miv.empty() && a[miv.back()] > a[i]) miv.pop_back() ; 28 mav.push_back(i) ; 29 miv.push_back(i) ; 30 while(!miv.empty() && !mav.empty() && a[mav.front()] - a[miv.front()] > r){ 31 if(mav.front()<miv.front()){ 32 last = mav.front() ; 33 mav.pop_front() ; 34 }else if(mav.front()>miv.front()){ 35 last = miv.front() ; 36 miv.pop_front() ; 37 }else{ 38 last = mav.front() ; 39 mav.pop_back() ; 40 miv.pop_back() ; 41 } 42 } 43 if(!mav.empty() && !miv.empty() && sum[i]-sum[last]>=s){ 44 ans = max(ans,i-last) ; 45 } 46 } 47 cout << ans << endl ; 48 49 return 0 ; 50 }
...