题目链接: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