记录一些好题吧。
题意 就是问题你 数组上L R的两个位置 能不能抵达。。
这题可以逆向dp (应该也可以正向 。就是逻辑反过来 然后我们用R来找L。)
// 定义f[N][20],ne[20];
// f[i][j]就是i下标 j位能够抵达的最近的地方。。
// 然后到时候就可以用f[i][j]<=R 来判断成立。。
// ne[j] 就是最近的j位置是1 的下标位置。
#include <bits/stdc++.h>
using namespace std;
#define easy_code ios::sync_with_stdio(0), cin.tie(nullptr)
#define endl '\n'
#define int long long
#define ar array<int, 2>
#define arr array<int, 3>
int T, n, m, k, inf = 1e18;
int mod = 998244353; // 1e9+7;
const int N = 301314;
int f[N][20], ne[N];
signed main()
{
easy_code;
#ifdef DEBUG
freopen("../1.in", "r", stdin);
#endif
cin >> n >> m;
int a[n + 1];
for (int i = 1; i <= n; ++i)
cin >> a[i];
memset(f, 0x3f, sizeof f);
for (int i = n; i; i--)
{
for (int j = 0; j < 20; ++j)
if (a[i] >> j & 1)
f[i][j] = i;
else
{
for (int k = 0; k < 20; ++k)
if (ne[k] != 0 && a[i] >> k & 1)
f[i][j] = min(f[i][j], f[ne[k]][j]);
//这个是核心递推关系。
// 有点像嫁接。。
//就像我开的杂货店没有卖糖(j位置没有1)。。
//(假如我们规定有卖同种货物的店之间是相通的)
//那我店里有盐k 我们就去最近的也有卖盐的店 问他最近的卖糖的店在哪里。
}
for (int j = 0; j < 20; ++j)
if (a[i] >> j & 1)
ne[j] = i;
}
while (m--)
{
int i, j;
cin >> i >> j;
bool ok = 0;
for (int k = 0; k < 20; ++k)
if ((a[j] >> k & 1) && f[i][k] <= j)
ok = 1;
cout << (ok ? "Shi" : "Fou") << endl;
}
};
// 为啥继承ne[k]的位置 就能保证是最优解。。
// 我的理解是 因为逆向的每个下标位置 都会实时的更新f[i][j] 其中j的答案。。
// 而ne[k] 又是记录的最近的f[ne[k]][j]的答案。。
// 所以继承f[ne[k]][j] 就是j的最优解。。
// 。。。感觉还是有点绕。。