单调队列就是队列中的元素是单调递增或递减的。比如把 5 2 3 1 4 入队:
减:、、、、、、、、、、、增:
5 、、、、、、、、、、、、5
5 2 、、、、、、、、、、、2
5 3 、、、、、、、、、、、2 3
5 3 1、、、、、、、、 、、1
5 4 、、、、、、、、、、、1 4
这个还是好理解的,但是,我们得会用单调队列这一特性去解决题目,抽象出题目中有类似的操作。
题意:输入3个数n a ,b .
1.Si = Ai mod B ;
2. Ti = Min{ Sk | i-A <= k <= i, k >= 1};
求Ti的乘积%b;
由于n的数据范围10^7,普通遍历肯定超时。
前几篇博客说过了,单调队列求区间最值。
做了这道题,我知道了一件事:stl双端队列超时啊啊啊啊啊啊啊啊!!!
贴上超时代码:
<pre name="code" class="cpp">#include <stdio.h>
#include <deque>
using namespace std;
int main()
{
int n,a,b;
while(scanf("%d %d %d",&n,&a,&b)!=EOF)
{
deque <int > di,v; //分别记录下标和值
int sum=1,s=1;
for(int i=1;i<=n;i++)
{
s=(s*a)%b;
while(!v.empty() && v.back()>s) di.pop_back(),v.pop_back();//维护单调队列
di.push_back(i),v.push_back(s);
while(i-di.front()>a) di.pop_front(),v.pop_front();//元素个数大于a,出队
sum*=v.front();
sum%=b;
}
printf("%d\n",sum);
}
return 0;
}
下面是数组模拟的单调队列:
#include <stdio.h>
int main()
{
int n,a,b;
int id[100005],v[100005]; //记录下标和值
while(scanf("%lld %lld %lld",&n,&a,&b)!=EOF)
{
int k1=1,k2=1; //队列头尾
long long sum=1,s=1;
for(int i=1;i<=n;i++)
{
s=(s*a)%b;
while(k1!=k2 && v[k2-1]>s) --k2; //维护单调队列
id[k2]=i,v[k2++]=s; //入队
while(i-id[k1]>a) ++k1; //元素个数大于a个,出队
sum*=v[k1]; //乘积
sum%=b;
}
printf("%lld\n",sum);
}
return 0;
}