1169E. And Reachability(DP+思路)
題目鏈接:傳送門
思路:
涉及到位運算,很容易想到按位考慮。
我們用表示第 個數可以到達第 位爲1的最小下標是多少,如果沒有則等於。
對於這個狀態方程,我們倒過來遞推,我們讓 從 開始遍歷到 ,並用 表示滿足 且 的第 位爲 的最小 ,初始化爲。
假設當前爲 ,考慮 第 位
- 如果 的第 位爲1,那麼
- 否則遍歷 所有位數爲 1 的位,假設爲 ,那麼
- 隨後更新
那麼對於每次查詢 ,我們枚舉 位數爲 的位, 假設爲 ,判斷是否存在 使得 即可。
(很容易想到如果滿足則必有解,且如果有解,必有上述表達式滿足,即兩問題等效)
代碼:
#include<bits/stdc++.h>
#define mset(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=3e5+10;
const int M=19;
int g[N][M],a[N],last[N];
int main()
{
int n,q;
scanf("%d%d",&n,&q);
for(int i=1; i<=n; ++i) scanf("%d",a+i);
for(int i=0; i<M; ++i) {
last[i]=n+1;
g[n+1][i]=n+1;
}
for(int i=n; i>=1; --i)
{
for(int j=0; j<M; ++j)
{
if((a[i]>>j)&1)
g[i][j]=i;
else
{
g[i][j]=n+1;
for(int k=0; k<M; ++k)
{
if((a[i]>>k)&1)
g[i][j]=min(g[i][j],g[last[k]][j]);
}
}
}
for(int j=0; j<M; ++j)
if((a[i]>>j)&1)
last[j]=i;
}
for(int o=0; o<q; ++o)
{
int x,y;
scanf("%d%d",&x,&y);
bool isok=false;
for(int i=0; i<M; ++i)
if((a[y]>>i)&1)
isok|=(g[x][i]<=y);
printf("%s\n",isok?"Shi":"Fou");
}
return 0;
}