题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5289
题面:
2 4 2 3 1 2 4 10 5 0 3 4 5 2 1 6 7 8 9
5 28HintFirst Sample, the satisfied groups include:[1,1]、[2,2]、[3,3]、[4,4] 、[2,3]
解题:
比赛的时候,怎么想都想不对,想去找最近的不合法的点,复杂度太高。看了题解才知道是用ST算法的。先前不知道,这是一篇很不错的ST算法的介绍。http://blog.csdn.net/david_jett/article/details/46990651
枚举左边端点,二分右端点,用ST算法判断该区间是否合法,直至右端点到极限(即二分的左右边界相遇或交叉)。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <map> #include <vector> #include <cmath> #include <algorithm> #define mod 1000000007 using namespace std; int t,n,k; int a[100100],minn[100010][20],maxn[100010][20],mid; long long ans; void Rmq_Init() { int m=19; for(int i=1;i<=n;i++) maxn[i][0]=minn[i][0]=a[i]; for(int i=1;i<=m;i++) for(int j=n;j;j--) { maxn[j][i]=maxn[j][i-1]; minn[j][i]=minn[j][i-1]; if(j+(1<<(i-1))<=n) { maxn[j][i]=max(maxn[j][i],maxn[j+(1<<(i-1))][i-1]); minn[j][i]=min(minn[j][i],minn[j+(1<<(i-1))][i-1]); } } } int Query_dif(int l,int r) { int m=floor(log((double)(r-l+1))/log(2.0)); int Max=max(maxn[l][m],maxn[r-(1<<m)+1][m]); int Min=min(minn[l][m],minn[r-(1<<m)+1][m]); return Max-Min; } int solve(int l) { int le,ri; le=l; ri=n; while(le<=ri) { mid=(le+ri)/2; if(Query_dif(l,mid)>=k) { ri=mid-1; } else { le=mid+1; } } /*if(Query_dif(l,mid)>=k) return mid-l; else return mid-l+1;*/ return ri-l+1; } int main() { scanf("%d",&t); while(t--) { ans=0; scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); } Rmq_Init(); for(int i=1;i<=n;i++) { ans=ans+solve(i); //cout<<i<<" "<<Query_dif(i,n)<<endl; //cout<<ans<<endl; } printf("%lld\n",ans); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/david_jett/article/details/47000085