本文主要是介绍CF1168C And Reachability,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Toad Pimple 有一个整数数组 a 1 , ⋯ , a n a_1,\cdots,a_n a1,⋯,an,我们称 x x x到 y y y可达当且仅当:
- x < y x<y x<y
- 存在一个数组 p p p,其中 x = p 1 < p 2 < . . . < p k = y x=p_1<p_2<...<p_k=y x=p1<p2<...<pk=y,并且对于任意 1 ≤ i < k 1\le i<k 1≤i<k,满足 a p i & a p i + 1 > 0 a_{p_i}\&a_{p_{i+1}}>0 api&api+1>0
现在给定 Q Q Q组下标 ( X i , Y i ) (X_i,Y_i) (Xi,Yi),请检查它们是否可达。
考虑从 y y y 跳到 x x x,如果我们可以找到一个 a i a_i ai 满足第 j j j 位是 1 1 1 且 a l a_l al 在这一位也是 1 1 1,并且 r r r 可以跳到这个位置 i i i,就是可行的。
显然,我们要尽可能让这个位置贴近 r r r,因为这样更有“优势”,可以让更多的 l l l 可行。
设 f i , j f_{i,j} fi,j 表示一个最大的下标 x x x 满足小于等于 i i i, a x a_x ax 第 j j j 位是 1 1 1。
有朴素转移: f i , j = max k = 1 i − 1 f k , j f_{i,j}=\max\limits_{k=1}^{i-1}f_{k,j} fi,j=k=1maxi−1fk,j,转移条件 a i & a k > 0 a_i\&a_k>0 ai&ak>0;特殊地,当 a i a_i ai 第 j j j 为是 1 1 1 时, f i , j = i f_{i,j}=i fi,j=i。
这是 O ( n 2 ) O(n^2) O(n2) 的,思考如何优化。
发现转移条件 a i & a k > 0 a_i\&a_k>0 ai&ak>0,可以转换为枚举第 x x x 位,如果 a i a_i ai 和 a k a_k ak 的第 x x x 为都为 1 1 1,这样就可以转移。
又有性质 f i , j f_{i,j} fi,j 随 i i i 单调递增,那么肯定是选最大的 k k k 一定最优。
所以用 p r e j pre_j prej 记录当前上一个下标 x x x 满足 a x a_x ax 的第 j j j 位为 1 1 1。转移就变成
f i , j = max k = 0 m f p r e k , j f_{i,j}=\max\limits_{k=0}^{m}f_{pre_{k},j} fi,j=k=0maxmfprek,j
对每个 i i i 转移完后记得更新 p r e j pre_j prej。
时间复杂度 O ( n log 2 n + q log n ) O(n\log^2n+q\log n) O(nlog2n+qlogn)
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+1,NN=19;
int n,q,a[N],f[N][NN+1],pre[NN];
int main()
{scanf("%d%d",&n,&q);for(int i=1;i<=n;i++) scanf("%d",&a[i]);for(int i=1;i<=n;i++){for(int j=0;j<NN;j++){for(int k=0;k<NN;k++){if(a[i]>>k&1){f[i][j]=max(f[i][j],f[pre[k]][j]);}}}for(int j=0;j<NN;j++){if(a[i]>>j&1){pre[j]=i;f[i][j]=max(f[i][j],i);}}}for(int i=1,x,y;i<=q;i++){scanf("%d%d",&x,&y);for(int j=0;j<NN;j++){if(a[x]>>j&1){if(f[y][j]>=x){puts("Shi");goto a;}}}puts("Fou");a:;}
}
这篇关于CF1168C And Reachability的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!