您的位置:首页 > 其它

没参加的2015百度之星——找连续数

2015-07-20 16:45 281 查看
传送门: http://acm.hdu.edu.cn/showproblem.php?pid=5247
Problem Description

小度熊拿到了一个无序的数组,对于这个数组,小度熊想知道是否能找到一个k 的区间,里面的 k 个数字排完序后是连续的。

现在小度熊增加题目难度,他不想知道是否有这样的 k 的区间,而是想知道有几个这样的 k 的区间。

 

Input

输入包含一组测试数据。

第一行包含两个整数n,m,n代表数组中有多少个数字,m 代表针对于此数组的询问次数,n不会超过10的4次方,m 不会超过1000。第二行包含n个正整数,第 I 个数字代表无序数组的第 I 位上的数字,数字大小不会超过2的31次方。接下来 m 行,每行一个正整数 k,含义详见题目描述,k 的大小不会超过1000。

 

Output

第一行输"Case #i:"。(由于只有一组样例,只输出”Case #1:”即可)

然后对于每个询问的 k,输出一行包含一个整数,代表数组中满足条件的 k 的大小的区间的数量。

 

Sample Input

6 2
3 2 1 4 3 5
3
4

 

Sample Output

Case #1:
2
2

 

Source

2015年百度之星程序设计大赛
- 初赛(1)

 

想法一:

n的规模1w左右,想想也是T的,不过还是写了下。预处理所有区间是否是连续区间,并保存结果ans[k]。

判断连续用线段树,总的复杂度为
nnlogn+m

T了。

想法二:

换个暴力姿势,不预处理,在线处理。对于k,暴力所有k区间。总的时间复杂度
n+m*(n-k)*k

AC了。

技巧:用区间max-min=k-1  以及 hash判重  来判断连续区间。

数据水水过了,但正解并不似这样的。待续。。。。

/**********************************************
暴力枚举区间[i,j],区间连续max()-min()=j-i
复杂度 O(nnlogn)
Bug 区间内部数没有判重
结果 TLE
**********************************************/
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct node{
int mi,ma;
}tree[10001*4];
void build(int rt,int l,int r){
if(l==r){
int x;scanf("%d",&x);
tree[rt].mi=tree[rt].ma=x;
return ;
}
int m=(l+r)>>1;
build(rt*2,l,m);
build(rt*2+1,m+1,r);
tree[rt].mi=min(tree[rt*2].mi,tree[rt*2+1].mi);
tree[rt].ma=max(tree[rt*2].ma,tree[rt*2+1].ma);
}
node query(int L, int R,int rt , int l,int r){
if(L==l&&R==r)
return tree[rt];
int m=(l+r)>>1;
if(R<=m)return query(L,R,rt*2,l,m);
else if(m+1<=L)return query(L,R,rt*2+1,m+1,r);
else{
node res,tmp1,tmp2;
tmp1=query(L,m,rt*2,l,m);
tmp2=query(m+1,R,rt*2+1,m+1,r);
res.mi=min(tmp1.mi,tmp2.mi);
res.ma=max(tmp1.ma,tmp2.ma);
return res;
}
}
int ans[10001];
int main(){
int n,m;
int CA=1;
while(~scanf("%d%d",&n,&m)){
build(1,1,n);
memset(ans,0,sizeof ans);
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++){
node tmp=query(i,j,1,1,n);
if(tmp.ma-tmp.mi == j-i)
ans[j-i+1]++;
}
printf("Case #%d:\n",CA++);
while(m--){
int k;scanf("%d",&k);
printf("%d\n",ans[k]);
}
}
return 0;
}

/**********************************************
在线处理k长区间,用hash判重 & max - min
**********************************************/
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,m;
int a[10001];
int mark[10001];
int ans[10001];
int main(){
int CA=1;
while(~scanf("%d%d",&n,&m)){
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
memset(mark,0,sizeof mark);
memset(ans,-1,sizeof ans);
printf("Case #%d:\n",CA++);
while(m--){
int k;scanf("%d",&k);
if(k==1){printf("%d\n",n);continue;}
if(ans[k]!=-1){printf("%d\n",ans[k]);continue;}
ans[k]=0;
for(int i=1;i+k-1<=n;i++){
int j=i+k-1;
int mi=a[i],ma=a[i];
bool ok = true;
for(int z=i,x=a[i];z<=j;z++){
if(mi>a[z])mi=a[z];
if(ma<a[z])ma=a[z];
}
if(ma-mi==k-1){
for(int z=i,x=mi;z<=j;z++)
mark[x++]=0;
for(int z=i;z<=j;z++){

4000
mark[a[z]]++;
if(mark[a[z]]!=1)
ok=false;
}
if(ok){
//                        cout<<i<<" "<<j<<endl;
ans[k]++;
}
}
}
printf("%d\n",ans[k]);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息