Time Limit: 3000MS | Memory Limit: 65536K | |||
Total Submissions: 36 | Accepted: 2 |
Description
有一天,小Q给了小J一些数字,让小J帮忙找到其中最大的数,由于小J是一个程序猿,当然写了一个代码很快的解决了这个问题。这时,邪恶的小Y又出现了,他问小J,假如我只需要知道这些数字中的某个区间的最大值,你还能做嘛?小J经过七七四十九天的思考,终于完美的解决了这道题目,这次,他想也让小Y尝尝苦头,于是他问小Y,我现在想知道存在多少不同的区间的最大值大于等于k,你还能做吗?这次,小Y犯了难,他来请教身为程序猿的你。
Hint:一个区间指al, al+1, …, ar,这一段的数且l <= r,一个区间的最大值指max{ al, al+1, …, ar },两个区间[l1, r1]、 [l2, r2]不同当且仅当l1不等于l2或r1不等于r2。
Input
第一行为一个整数T(1<=T<=5),代表样例数。接下来每组样例的第一行读入一个正整数n(1<=n<=100000)。接下来一行读入n个正整数ai (1 <= ai <= 100000)。接下来一行一个正整数Q(1<=Q<=100000),表示有Q组询问。接下来Q行,每行一个正整数k(1<= k <=100000)。
Output
对于每组样例,先输出“Case #ca:”,ca从1开始。接下来Q行,每行一个正整数,表示存在多少区间大于等于k。
Sample Input
1 3 1 2 3 3 1 2 3
Sample Output
Case #1: 6 53
这题可以用单调队列做,先处理出以每个数为最大值的区间,然后再把询问都读入,然后按询问的值从大到小排序,然后每次把数字大于等于询问值的区间都加进去,加进去的值为(idx-l[i]+1)*(r[i]-idx+1),注意,如果出现5 4 5的情况,即第一个5和第二个5的边界是相同的,那么就只能加一次。
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<string> #include<algorithm> using namespace std; typedef long long ll; #define inf 99999999 #define pi acos(-1.0) #define maxn 100050 ll a[maxn]; struct node{ int l,r,idx; }temp; vector<node>pos[maxn]; vector<node>::iterator it; int q[1111111][2],l[maxn],r[maxn]; struct node1{ int num,idx; }question[maxn]; ll ans[maxn]; bool cmp(node1 a,node1 b){ return a.num>b.num; } int main() { int n,m,i,j,T,front,rear,t,cas=0; scanf("%d",&T); while(T--) { scanf("%d",&n); for(i=1;i<=n;i++){ scanf("%d",&a[i]); } for(i=1;i<=100000;i++)pos[i].clear(); front=1;rear=0; for(i=1;i<=n;i++){ while(front<=rear && q[rear][0]<=a[i])rear--; if(front>rear)l[i]=1; else l[i]=q[rear][1]+1; rear++; q[rear][0]=a[i]; q[rear][1]=i; } front=1;rear=0; for(i=n;i>=1;i--){ while(front<=rear && q[rear][0]<=a[i])rear--; if(front>rear)r[i]=n; else r[i]=q[rear][1]-1; rear++; q[rear][0]=a[i]; q[rear][1]=i; } for(i=1;i<=n;i++){ temp.l=l[i]; temp.r=r[i]; temp.idx=i; pos[a[i] ].push_back(temp); } scanf("%d",&t); for(i=1;i<=t;i++){ scanf("%d",&question[i].num); question[i].idx=i; } sort(question+1,question+1+t,cmp); ll num=100005; ll sum=0; for(i=1;i<=t;i++){ while(num>=question[i].num){ ll pre=0,ll,rr; for(it=pos[num].begin();it!=pos[num].end();it++){ temp=*it; ll=temp.l; if(temp.l<=pre){ ll=pre+1; } rr=temp.r; sum+=(temp.idx-ll+1)*(rr-temp.idx+1); pre=temp.idx; } num--; } ans[question[i].idx]=sum; } cas++; printf("Case #%d:\n",cas); for(i=1;i<=t;i++){ printf("%lld\n",ans[i]); } } return 0; }