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;
}
浙公网安备 33010602011771号