官方题解:http://blog.sina.com.cn/duoxiao2015
第一场开始时都还没放暑假。。。队友用我感觉会超时的代码AC了两题,囧。。。
HDOJ5288
题意:给一个序列,求共有多少个找不到任意两个不同数是整除关系的连续子序列,结果mod 1e9+7
思路:见官方题解O(nsqrt(n))的算法,但是没看懂,然后下图是大牛给我的解说,看完就懂了
PS:O(n^2)肯定会超时,但是数据太水,队友用O(n^2)的方法过了,就不贴代码了
HDOJ5289
题意:给一个长度为n的序列,为共有多少给连续子序列中最大值与最小值之差小于k
思路:一看到这题,我就想去用O(nlogn)的RMQ+二分,先RMQ预处理,然后对于每个起始位置二分查找结束位置
PS:赛后想起可以用O(n)单调队列直接扫一遍就可以了
PS2:O(n^2)肯定会超时,但是数据太水,队友居然又用O(n^2)的方法过了!!!
PS3:大白书P198页的RMQ的代码有误,害我RE了几次
以下是我写的RMQ+二分的代码
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long LL;
const int MAXN=100000+10;
const int MOD=1e9+7;
int dmax[MAXN][20],dmin[MAXN][20],a[MAXN];
int T,n,kk;
//输入外挂
template <class T>
inline bool read(T &ret) {
char c; int sgn;
if(c=getchar(),c==EOF) return 0; //EOF
while(c!='-'&&(c<'0'||c>'9')) c=getchar();
sgn=(c=='-')?-1:1;
ret=(c=='-')?0:(c-'0');
while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
ret*=sgn;
return 1;
}
void RMQ_init(){
for(int i=1;i<=n;i++)
dmax[i][0]=a[i];
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
dmax[i][j]=max(dmax[i][j-1],dmax[i+(1<<(j-1))][j-1]);
for(int i=1;i<=n;i++)dmin[i][0]=a[i];
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
dmin[i][j]=min(dmin[i][j-1],dmin[i+(1<<(j-1))][j-1]);
}
int RMQmin(int L,int R){
int k=0;
while((1<<(k+1))<=R-L+1)k++;
return min(dmin[L][k],dmin[R-(1<<k)+1][k]);
}
int RMQmax(int L,int R){
int k=0;
while((1<<(k+1))<=R-L+1)k++;
return max(dmax[L][k],dmax[R-(1<<k)+1][k]);
}
int RMQ(int l,int r){
return RMQmax(l,r)-RMQmin(l,r);
}
int bSearch(int x){
int l=x,r=n;
while(l<=r){
int m=(l+r)>>1;
if(RMQ(x,m)<kk)l=m+1;
else r=m-1;
}
return r;
}
LL work(){
LL res=0;
for(int i=1;i<=n;i++){
int j=bSearch(i);
res+=j-i+1;
}
return res;
}
int main(){
#ifdef DEBUG
freopen("CBin.txt","r",stdin);
//freopen("CBout.txt","w",stdout);
#endif
read(T);
while(T--){
read(n);
read(kk);
for (int i=1;i<=n;++i)read(a[i]);
RMQ_init();
cout<<work()<<"\n";
}
return 0;
}