您的位置:首页 > 大数据 > 人工智能

[HDU5741] Helter Skelter [2016 Multi-University Training Contest 2(2016多校联合训练2) H]

2016-07-28 21:09 721 查看

题意

给定01序列,每次询问是否存在连续区间使得0的个数为ai,1的个数为bi.

题解

对于一个固定的a,可行的b是一个区间.如果我们把所有可行的(a,b)画在二维平面上,



可以观察到这个可行区域一定是连通的,且上下界有一些和x轴y轴平行的线段组成.于是我们需要求出这个区域的上下边界.对于上边界中在线段转折处的点,一定是一个从1开始, 以1结尾的序列长度,下边界的线段转折点处的点,一定是一个从0开始, 以0结尾的序列长度.

枚举连续的以01…10序列并排序,求下边界,枚举连续的10…01序列求上边界,这就求出了可行区域的上下边界.

这样对每一个询问(a,b)我们二分求出与a对应的b的可行范围,就可以判断了.

代码

/****************************************\
* Author : ztx
* Title  : Helter Skelter
* ALG    :
* CMT    :
* Time   :
\****************************************/

#include <cstdio>
#define Rep(i,l,r) for(i=(l);i<=(r);i++)
#define rep(i,l,r) for(i=(l);i< (r);i++)
#define Rev(i,r,l) for(i=(r);i>=(l);i--)
#define rev(i,r,l) for(i=(r);i> (l);i--)
typedef long long ll ;
typedef double lf ;
int CH , NEG ;
template <typename TP>inline void read(TP& ret) {
ret = NEG = 0 ; while (CH=getchar() , CH<'!') ;
if (CH == '-') NEG = true , CH = getchar() ;
while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ;
if (NEG) ret = -ret ;
}
template <typename TP>inline void readc(TP& ret) {
while (ret=getchar() , ret<'!') ;
while (CH=getchar() , CH>'!') ;
}
template <typename TP>inline void reads(TP *ret) {
ret[0]=0;while (CH=getchar() , CH<'!') ;
while (ret[++ret[0]]=CH,CH=getchar(),CH>'!') ;
ret[ret[0]+1]=0;
}

#include <algorithm>

#define  maxn  1010LL
#define  maxt  1000010LL
#define  infi  1000000010LL

struct node {
int a , b ;
bool operator < (const node&B) const {
if (a == B.a) return b < B.b ;
return a < B.a ;
}
} up[maxt] , down[maxt] , tmp ; int totd , totu ;

int a[maxn] , s0[maxn] , s1[maxn] ;

int main() {
int n , m , max0 , max1 , T , i , j , k , aa , bb ;
//  #define READ
#ifdef  READ
freopen(".in" ,"r",stdin ) ;
freopen(".out","w",stdout) ;
#endif
for (read(T) ; T --> 0 ; ) {
read(n) , read(m) ;
s0[0] = s1[0] = a[0] = a[n+1] = max0 = max1 = 0 ;
Rep (i,1,n) {
read(a[i]) ;
s0[i] = s0[i-1] , s1[i] = s1[i-1] ;
if (i&1) s0[i] += a[i] , max0 = std::max(max0,a[i]) ;
else s1[i] += a[i] , max1 = std::max(max1,a[i]);
}
totd = totu = 0 ;
for (k = 1 ; k <= n ; k += 2)
for (i = 1 ; j = i+k-1 , j <= n ; i += 2) {
down[++totd] = (node){s0[j]-s0[i-1],s1[j]-s1[i-1]} ;
up[++totu] = (node){s0[j]-s0[i-1],s1[j]-s1[i-1]+a[i-1]+a[j+1]} ;
}
up[++totu] = (node){0,max1} ;/// !!! !!! !!!
std::sort(down+1,down+totd+1) ;
std::sort(up+1,up+totu+1) ;
/// Get Down find a lowest rising path
k = totd ;
for (totd = 1 , i = 2 ; i <= k ; i ++ )
if (down[i].a != down[totd].a) {
while (totd && down[totd].b >= down[i].b) totd -- ;
down[++totd] = down[i] ;
}
down[++totd] = (node){infi,infi} ;
/// Get Up find a highest rising path
k = totu ;
for (totu = 1 , i = 2 ; i <= k ; i ++ )
if (up[i].a == up[totu].a) up[totu] = up[i] ;
else if (up[i].b > up[totu].b) up[++totu] = up[i] ;
up[++totu] = (node){infi,-1} ;
/// Answer
while (m -- ) {
read(aa) , read(bb) ;
if (!aa) { putchar((bb<=max1)+'0') ; continue ; }
if (!bb) { putchar((aa<=max0)+'0') ; continue ; }
if (aa > s0
|| bb > s1
) { putchar('0') ; continue ; }
i = std::upper_bound(down+1,down+totd+1,(node){aa,-1})-down ;
if (down[i].b > bb) { putchar('0') ; continue ; }
i = std::upper_bound(up+1,up+totu+1,(node){aa,infi})-up ;
if (up[i-1].b < bb) { putchar('0') ; continue ; }
putchar('1') ;
}
puts("") ;
}
#ifdef  READ
fclose(stdin) ; fclose(stdout) ;
#else
getchar() ; getchar() ;
#endif
return 0 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: