代码源挑战赛 Round 1
#1. [R1A]最大奇数
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
int res = -1;
for (int i = 1, x; i <= n; i++) {
cin >> x;
if (x % 2 == 0) continue;
res = max(res, x);
}
cout << res << "\n";
return 0;
}
#2. [R1B]砖块覆盖
对于行列均为偶数的情况可以用\(2\times 2\)拼出来。
对于行列有一个为偶数的情况,可以先用\(2\times 2\)拼,然后剩下一个\(1\times n\)的情况,并且\(n\)一定是偶数。
对于行列都是奇数,用\(2\times 2\)评完后,还剩下\(1\times n , 1\times (n - 1)\),因此无法拼成剩下的。
所有行列全奇数为No,剩下全是Yes。
#include <bits/stdc++.h>
using namespace std;
void solve(){
int x, y;
cin >> x >> y;
if ((x % 2) and (y % 2)) cout << "No\n";
else cout << "Yes\n";
}
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int T;
cin >> T;
while(T --) solve();
return 0;
}
#3. [R1C]区间求和
计算每一个数被多少个区间包含。
#include <bits/stdc++.h>
using namespace std;
using i64 = int64_t;
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
i64 res = 0;
for(int i = 1; i <= n ; i ++) {
i64 x;
cin >> x;
res += x * (i) * (n - i + 1);
}
cout << res;
return 0;
}
#4. [R1D]传送
每一个点只有一个唯一后继,所以图是一个内向基环树。用类似倍增求LCA的方式预处理在图上移动。
#include <bits/stdc++.h>
using i64 = int64_t;
using vi = std::vector<int>;
using std::cin, std::cout;
int main() {
std::ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
std::vector next(n + 1, vi(31));
for (int i = 1; i <= n; i++) {
cin >> next[i][0];
}
for (int j = 1; j < 31; j++)
for (int i = 1; i <= n; i++)
next[i][j] = next[next[i][j - 1]][j - 1];
int q;
cin >> q;
for (int x, t; q; q--) {
cin >> x >> t;
for (int i = 0; i < 31 and t > 0; i++) {
if (t & 1) x = next[x][i];
t >>= 1;
}
cout << x << "\n";
}
return 0;
}
#5. [R1E]过分的子区间
“过分的区间”可以理解为,区间中比\(x\)小的数小于\(k\)个。
这样的话,如果\([l,r]\)满足,则\([l,r-1]\)也满足,固定左端点,右端点满足二分性。
用前缀和维护出区间中小于\(x\)的数的个数。
#include <bits/stdc++.h>
using i64 = int64_t;
using vi = std::vector<int>;
using std::cin, std::cout;
int main() {
std::ios::sync_with_stdio(false), cin.tie(nullptr);
int n, k, z;
cin >> n >> k >> z;
vi pre(n + 1);
for (int i = 1, x; i <= n; i++) {
cin >> x;
if (x < z) pre[i] = 1;
}
for (int i = 1; i <= n; i++) pre[i] += pre[i - 1];
i64 res = 0;
for (int i = 1, ans, l, r, mid; i <= n; i++) {
l = i - 1, r = n, ans = -1;
while (l <= r) {
mid = (l + r) / 2;
if (pre[mid] - pre[i - 1] < k) ans = mid, l = mid + 1;
else r = mid - 1;
}
res += ans - i + 1;
}
cout << res;
return 0;
}
#6. [R1F]重复度不超过k的数
dp
\(f[i][j]\)表示前\(i\)个数字,用了\(j\)位的方案数。枚举当前数字用来\(l\)位,则从\(f[i-1][j - l]\)转移过来,填数字前有\(n - j + l\)个位置,选择\(l\)个位置,所以当前数字放置方法有\(C_{n - j + l} ^{l}\)种。
#include <bits/stdc++.h>
using i64 = int64_t;
using vi = std::vector<i64>;
using std::cin, std::cout;
const i64 mod = 998244353;
i64 power(i64 x, i64 y) {
i64 ans = 1;
while (y) {
if (y & 1) ans = ans * x % mod;
x = x * x % mod;
y /= 2;
}
return ans;
}
vi fact, invFact;
void init(int N) {
fact.resize(N + 1);
invFact.resize(N + 1);
fact[0] = 1;
for (int i = 1; i <= N; i++) fact[i] = fact[i - 1] * i % mod;
invFact[N] = power(fact[N], mod - 2);
for (int i = N; i >= 1; i--) invFact[i - 1] = invFact[i] * i % mod;
}
i64 C(int x, int y) {
return fact[x] * invFact[x - y] % mod * invFact[y] % mod;
}
int main() {
std::ios::sync_with_stdio(false), cin.tie(nullptr);
int n, m, k;
cin >> n >> m >> k;
init(n);
std::vector f(m + 1, vi(n + 1));
f[0][0] = 1;
for (int i = 1; i <= m; i++)
for (int j = 0; j <= k; j++)
for (int l = j; l <= n; l++)
f[i][l] = (f[i][l] + f[i - 1][l - j] * C(n - l + j, j)) % mod;
cout << f[m][n];
return 0;
}

浙公网安备 33010602011771号