1169E. And Reachability(DP+思路)

1169E. And Reachability(DP+思路)

題目鏈接:傳送門

思路:

涉及到位運算,很容易想到按位考慮。

我們用go[i][j]go[i][j]表示第 ii 個數可以到達第 jj 位爲1的最小下標是多少,如果沒有則等於n+1n+1

對於這個狀態方程,我們倒過來遞推,我們讓 iinn 開始遍歷到 11 ,並用last[k]last[k] 表示滿足 j>ij>iaja_j 的第 kk 位爲 11 的最小 jj ,初始化爲n+1n+1

假設當前爲 ii,考慮 第 jj

  • 如果 aia_i 的第 jj 位爲1,那麼go[i][j]=igo[i][j]=i
  • 否則遍歷 aia_i 所有位數爲 1 的位,假設爲 kk ,那麼go[i][j]=min(g[i][j],g[last[k]][j])go[i][j]=min(g[i][j],g[last[k]][j])
  • 隨後更新last[]last[]

那麼對於每次查詢x,yx,y ,我們枚舉 aya_y 位數爲 11 的位, 假設爲 kk,判斷是否存在 kk 使得go[x][k]ygo[x][k]\le y 即可。

(很容易想到如果滿足則必有解,且如果有解,必有上述表達式滿足,即兩問題等效)

代碼:

#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章