T1. 改写

如果两个数不同,那么一定存在一个 \(b\),使得其中一个数的第 \(b\) 位为 \(1\),另一个数为 \(0\)

这意味着,如果 \(\{a_i \vee x\}\) 中有至少两个不同的数,那么一定存在一个 \(b\),使得:

  • \(x\) 的第 \(b\) 位为 \(0\)
  • \(\{a_i\}\) 中存在一个元素的第 \(b\) 位为 \(1\)
  • \(\{a_i\}\) 中存在一个元素的第 \(b\) 位为 \(0\)

于是我们可以枚举这个 \(b\),判断条件2、条件3是否满足。如果满足,我们可以从高到低贪心地考虑 \(b\) 以外的每个二进制位,找到最大的合法的 \(x\)

时间复杂度为 \(O(30n)\)

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;
using ll = long long;

void solve() {
    int n, k;
    cin >> n >> k;
    
    vector<int> a(n);
    rep(i, n) cin >> a[i];
    
    ll ans = 0;
    rep(i, 30) {
        int cnt = 0;
        for (int x : a) cnt += x>>i&1;
        if (cnt == 0 or cnt == n) continue;
        
        ll now = 0;
        for (int j = 29; j >= 0; --j) {
            if (j == i) continue;
            if (now+(1<<j) > k) continue;
            now += 1<<j;
        }
        ans = max(ans, now);
    }
    
    cout << ans << '\n';
}

int main() {
    int t;
    cin >> t;
    
    while (t--) solve();
    
    return 0;
}

T2. 概括

考虑从小到大填数。

首先 \(p\) 的第一个元素必须是 \(a_1\),因为它是第一个最大值。
因此,我们有如下结论:

  • \(1\) 不能放在第一个位置,但其他地方都可以,因为它们不会影响前缀最大值。因此有 \(n-1\) 种可能。
  • \(2\) 不能放在第一个位置或 \(1\) 所在的位置,但其他地方都可以。有 \(n-2\) 种选择。
  • 同样,\(3\)\(n-3\) 个位置可以放置。
    \(\vdots\)
  • \(a_1-1\)\(n-(a_1-1)\) 种选择。

放好这些之后,正如前面所述,我们把 \(a_1\) 放在位置 \(1\)

之后注意,\(a_2\) 必须放在最左侧的空位,才能成为第二个最大值。
这样就确定了 \(a_1+1\) 个元素,因此

  • 元素 \(a_1+1\)\(n-(a_1+1)\) 种选择。
  • 元素 \(a_1+2\)\(n-(a_1+2)\) 种选择。
    \(\vdots\)
  • 元素 \(a_2-1\)\(n-(a_2-1)\) 种选择。

不难看出,这个过程会一直进行,直到我们放置 \(a_k = n\)

也就是说,对于每个不是 \(a_i\) 的整数 \(x\),它有 \(n-x\) 种选择。

因此,最终答案就是这些数的乘积,即

\[\prod_{\substack{x=1 \\ x \neq a_i}}^n (n-x) \]

可以在 \(\mathcal{O}(N)\) 时间内轻松计算。

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;
using ll = long long;

const int mod = 998244353;
//const int mod = 1000000007;
struct mint {
    ll x;
    mint(ll x=0):x((x%mod+mod)%mod) {}
    mint operator-() const {
        return mint(-x);
    }
    mint& operator+=(const mint a) {
        if ((x += a.x) >= mod) x -= mod;
        return *this;
    }
    mint& operator-=(const mint a) {
        if ((x += mod-a.x) >= mod) x -= mod;
        return *this;
    }
    mint& operator*=(const mint a) {
        (x *= a.x) %= mod;
        return *this;
    }
    mint operator+(const mint a) const {
        return mint(*this) += a;
    }
    mint operator-(const mint a) const {
        return mint(*this) -= a;
    }
    mint operator*(const mint a) const {
        return mint(*this) *= a;
    }
    mint pow(ll t) const {
        if (!t) return 1;
        mint a = pow(t>>1);
        a *= a;
        if (t&1) a *= *this;
        return a;
    }

    // for prime mod
    mint inv() const {
        return pow(mod-2);
    }
    mint& operator/=(const mint a) {
        return *this *= a.inv();
    }
    mint operator/(const mint a) const {
        return mint(*this) /= a;
    }
};
istream& operator>>(istream& is, mint& a) {
    return is >> a.x;
}
ostream& operator<<(ostream& os, const mint& a) {
    return os << a.x;
}

void solve() {
    int n, k;
    cin >> n >> k;
    
    vector<int> a(k);
    rep(i, k) cin >> a[i];
    
    mint ans = 1;
    int i = 0;
    for (int x = 1; x <= n; ++x) {
        if (x == a[i]) {
            i++;
            continue;
        }
        ans *= n-x;
    }
    
    cout << ans << '\n';
}

int main() {
    int t;
    cin >> t;
    
    while (t--) solve();
    
    return 0;
}