没参加的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;
}
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; }
相关文章推荐
- Mootools 1.2教程 定时器和哈希简介
- C#获取哈希加密生成随机安全码的类实例
- PowerShell中定义哈希散列(Hash)和调用例子
- PHP中创建和验证哈希的简单方法实探
- Perl 哈希的创建和引用介绍
- Perl 哈希Hash用法之入门教程
- perl哈希hash的常见用法介绍
- perl哈希的一个实例分析
- Go语言常见哈希函数的使用
- 线段树题集
- Data Structure - Week 16
- hashing (哈希)
- hdu1754
- HDU1394
- 敌兵布阵 (1)
- I Hate It (1)
- LCIS (2)
- A Simple Problem with Integers (2)
- Mayor's posters (3)
- Buy Tickets (3)