Diverse Word
长度不是 2626 的时候,往后加第一个没出现过的字符就行了。
否则找到最大的一个 ii 满足存在 ,然后把最小的 sjsj 换过来就行了。
#include <bits/stdc++.h>
using namespace std;
#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;
template <typename T> inline void Read(T &x) {
char c = getchar();
bool f = false;
for (x = 0; !isdigit(c); c = getchar()) {
if (c == '-') {
f = true;
}
}
for (; isdigit(c); c = getchar()) {
x = x * 10 + c - '0';
}
if (f) {
x = -x;
}
}
template <typename T> inline bool CheckMax(T &a, const T &b) {
return a < b ? a = b, true : false;
}
template <typename T> inline bool CheckMin(T &a, const T &b) {
return a > b ? a = b, true : false;
}
const int N = 30;
char s[N];
bool v[N];
int n;
int main() {
#ifdef wxh010910
freopen("d.in", "r", stdin);
#endif
scanf("%s", s), n = strlen(s);
for (int i = 0; i < n; ++i) {
v[s[i] - 'a'] = true;
}
if (n != 26) {
for (int i = 0; i < 26; ++i) {
if (!v[i]) {
s[n] = i + 'a', puts(s);
return 0;
}
}
}
for (int i = n - 1; ~i; --i) {
for (int j = s[i] - 'a' + 1; j < 26; ++j) {
if (!v[j]) {
s[i] = j + 'a', s[i + 1] = 0, puts(s);
return 0;
}
}
v[s[i] - 'a'] = false;
}
puts("-1");
#ifdef wxh010910
Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
return 0;
}
GCD Sequence
小范围打表求出 1212 以内长度为 88 的构造,然后每次加 就行了。
#include <bits/stdc++.h>
using namespace std;
#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;
template <typename T> inline void Read(T &x) {
char c = getchar();
bool f = false;
for (x = 0; !isdigit(c); c = getchar()) {
if (c == '-') {
f = true;
}
}
for (; isdigit(c); c = getchar()) {
x = x * 10 + c - '0';
}
if (f) {
x = -x;
}
}
template <typename T> inline bool CheckMax(T &a, const T &b) {
return a < b ? a = b, true : false;
}
template <typename T> inline bool CheckMin(T &a, const T &b) {
return a > b ? a = b, true : false;
}
int n, m;
int main() {
#ifdef wxh010910
freopen("d.in", "r", stdin);
#endif
Read(n);
if (n == 3) {
puts("2 5 63");
return 0;
}
if (n & 1) {
int a[8] = {6, 2, 10, 3, 9, 4, 8, 12};
for (int i = 0; i < n; ++i) {
printf("%d%c", a[i & 7], i == n - 1 ? '\n' : ' ');
a[i & 7] += 12;
}
} else {
int a[8] = {2, 10, 3, 9, 4, 8, 6, 12};
for (int i = 0; i < n; ++i) {
printf("%d%c", a[i & 7], i == n - 1 ? '\n' : ' ');
a[i & 7] += 12;
}
}
#ifdef wxh010910
Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
return 0;
}
Remainder Game
逐位确定,每次建出转移图暴力判断是否可达。
#include <bits/stdc++.h>
using namespace std;
#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;
template <typename T> inline void Read(T &x) {
char c = getchar();
bool f = false;
for (x = 0; !isdigit(c); c = getchar()) {
if (c == '-') {
f = true;
}
}
for (; isdigit(c); c = getchar()) {
x = x * 10 + c - '0';
}
if (f) {
x = -x;
}
}
template <typename T> inline bool CheckMax(T &a, const T &b) {
return a < b ? a = b, true : false;
}
template <typename T> inline bool CheckMin(T &a, const T &b) {
return a > b ? a = b, true : false;
}
const int N = 55;
int n, a[N], b[N];
LL ans, adj[N];
bool v[N];
inline bool Check() {
for (int i = 0; i <= 50; ++i) {
adj[i] = 1LL << i;
for (int j = 1; j <= i; ++j) {
if (v[j]) {
adj[i] |= adj[i % j];
}
}
}
for (int i = 1; i <= n; ++i) {
if (!(adj[a[i]] >> b[i] & 1)) {
return false;
}
}
return true;
}
int main() {
#ifdef wxh010910
freopen("d.in", "r", stdin);
#endif
Read(n);
for (int i = 1; i <= n; ++i) {
Read(a[i]);
}
for (int i = 1; i <= n; ++i) {
Read(b[i]);
}
for (int i = 1; i <= 50; ++i) {
v[i] = true;
}
if (!Check()) {
puts("-1");
return 0;
}
for (int i = 50; i; --i) {
v[i] = false;
if (!Check()) {
v[i] = true, ans += 1LL << i;
}
}
printf("%lld\n", ans);
#ifdef wxh010910
Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
return 0;
}
Shopping
实际上是要最小化车往返次数,首先有一种策略就是按照编号从小到大访问,考虑优化这个策略,记 li=[ti≤2xi]li=[ti≤2xi] ,即从右边进去能否从右边出来, ri=[ti≤2(L−xi)]ri=[ti≤2(L−xi)] ,即从左边进去能否从左边出来,那么对于 i<j,li=rj=1i<j,li=rj=1 ,可以通过先走 jj 再走 的方式减少一次次数,然后就是类似于求一个匹配,贪心即可,注意要特判要经过所有点。
#include <bits/stdc++.h>
using namespace std;
#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;
template <typename T> inline void Read(T &x) {
char c = getchar();
bool f = false;
for (x = 0; !isdigit(c); c = getchar()) {
if (c == '-') {
f = true;
}
}
for (; isdigit(c); c = getchar()) {
x = x * 10 + c - '0';
}
if (f) {
x = -x;
}
}
template <typename T> inline bool CheckMax(T &a, const T &b) {
return a < b ? a = b, true : false;
}
template <typename T> inline bool CheckMin(T &a, const T &b) {
return a > b ? a = b, true : false;
}
const int N = 300005;
int n, m, x, y, a[N];
bool l[N], r[N];
LL ans;
int main() {
#ifdef wxh010910
freopen("d.in", "r", stdin);
#endif
Read(n), Read(m);
for (int i = 1; i <= n; ++i) {
Read(a[i]);
}
for (int i = 1, t; i <= n; ++i) {
Read(t);
if (t % (m << 1) == 0) {
ans += t;
} else {
ans += 1LL * (t / (m << 1) + 1) * (m << 1), t %= m << 1;
if (t <= a[i] << 1) {
l[i] = true;
}
if (t <= m - a[i] << 1) {
r[i] = true;
}
}
}
for (int i = 1; i < n; ++i) {
if (x && r[i]) {
if (l[i]) {
++y;
}
--x, ans -= m << 1;
} else if (!l[i] && r[i]) {
if (y) {
--y, ++x;
}
} else if (l[i]) {
++x;
}
}
if (!r[n]) {
ans += m << 1;
}
printf("%lld\n", ans);
#ifdef wxh010910
Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
return 0;
}
Median Replace
考虑合法的序列长什么样:往序列最后添加一个 11 ,记 表示第 ii 个 和第 i−1i−1 个 11 之间 的个数,那么对于 ai≥3ai≥3 ,可以不断操作让 aiai 减去 22 ,所以之后认为 。
考虑操作对 aiai 的影响,只有两种情况:将两个相邻 00 合并成一个 或者将相邻的 x,yx,y 合并成 x+y−1x+y−1 ,不难发现 ai=1ai=1 是没有用的,可以直接去掉。而合并两个偶数一定会变成一个奇数,相当于删除两个相邻的数。最后序列要变成 0,00,0 ,那么就是找到一对 (i,j)(i,j) 满足 ai=aj=0ai=aj=0 ,并且 ii 前面和 后面都有偶数个元素。
这样就可以用一个DP求出合法的序列个数了。
#include <bits/stdc++.h>
using namespace std;
#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;
template <typename T> inline void Read(T &x) {
char c = getchar();
bool f = false;
for (x = 0; !isdigit(c); c = getchar()) {
if (c == '-') {
f = true;
}
}
for (; isdigit(c); c = getchar()) {
x = x * 10 + c - '0';
}
if (f) {
x = -x;
}
}
template <typename T> inline bool CheckMax(T &a, const T &b) {
return a < b ? a = b, true : false;
}
template <typename T> inline bool CheckMin(T &a, const T &b) {
return a > b ? a = b, true : false;
}
const int N = 300005;
const int mod = 1e9 + 7;
int n, ans, suf[N], f[N][2][2][3];
char s[N];
int main() {
#ifdef wxh010910
freopen("d.in", "r", stdin);
#endif
scanf("%s", s), n = strlen(s), f[0][0][0][0] = suf[n] = 1;
for (int i = n - 1; ~i; --i) {
suf[i] = 1LL * suf[i + 1] * ((s[i] == '?') + 1) % mod;
}
for (int i = 0; i < n; ++i) {
if (s[i] != '1') {
for (int j = 0; j < 2; ++j) {
for (int k = 0; k < 2; ++k) {
for (int l = 0; l < 3; ++l) {
f[i + 1][j][k][(l & 1) + 1] = (f[i + 1][j][k][(l & 1) + 1] + f[i][j][k][l]) % mod;
}
}
}
}
if (s[i] != '0') {
for (int j = 0; j < 2; ++j) {
for (int k = 0; k < 2; ++k) {
if (!j && !k) {
f[i + 1][1][1][0] = (f[i + 1][1][1][0] + f[i][j][k][0]) % mod;
} else if (j && k) {
ans = (1LL * f[i][j][k][0] * suf[i + 1] + ans) % mod;
} else {
f[i + 1][!j][k][0] = (f[i + 1][!j][k][0] + f[i][j][k][0]) % mod;
}
f[i + 1][j][k][0] = (f[i + 1][j][k][0] + f[i][j][k][1]) % mod;
f[i + 1][!j][k][0] = (f[i + 1][!j][k][0] + f[i][j][k][2]) % mod;
}
}
}
}
printf("%d\n", (ans + f[n][1][1][0]) % mod);
#ifdef wxh010910
Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
return 0;
}
Checkers
因为 XX 很大,可以认为是 维向量进行运算,因为向量每一维是什么并不重要,只要维护每一维值的集合就行了。不难发现,每一维的值一定是 2i2i 或者 −2i−2i ,并且每个集合值的总和为 11 ,且满足 和 −1−1 出现次数总和恰好为 11 。
以上条件是不够的,事实上还需要一个条件:对于任意 ,可以通过调整绝对值为 2i2i 的符号来让绝对值不超过 2i2i 的数和为 11 ,必要性显然,充分性可以考虑归纳法,对于一个集合 ,如果能分成 2A2A 和 −B−B ,A,BA,B 也满足这个条件,那就证完了。
不妨设 −1∈S−1∈S ,记 kk 为最小的出现过的 ,如果对于 1≤i<k1≤i<k , −2i−2i 出现过至少两次,那么可以构造 A={−20,−21,−22,⋯,−2k−2,2k−1}A={−20,−21,−22,⋯,−2k−2,2k−1} ,可以验证满足条件。否则记最小的只出现过一次的是 −2i−2i ,如果 i=1i=1 ,那么 B={20}B={20} 也满足条件,否则 −1−2∑i−1j=12j<−2i−1−1−2∑j=1i−12j<−2i−1 ,就不是合法的集合了。另一种情况同理。之后DP很简单就不细说了。
#include <bits/stdc++.h>
using namespace std;
#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;
template <typename T> inline void Read(T &x) {
char c = getchar();
bool f = false;
for (x = 0; !isdigit(c); c = getchar()) {
if (c == '-') {
f = true;
}
}
for (; isdigit(c); c = getchar()) {
x = x * 10 + c - '0';
}
if (f) {
x = -x;
}
}
template <typename T> inline bool CheckMax(T &a, const T &b) {
return a < b ? a = b, true : false;
}
template <typename T> inline bool CheckMin(T &a, const T &b) {
return a > b ? a = b, true : false;
}
const int N = 105;
const int mod = 1e9 + 7;
int n, c[N][N], f[N][N];
int main() {
#ifdef wxh010910
freopen("d.in", "r", stdin);
#endif
Read(n);
for (int i = 0; i <= n; ++i) {
c[i][0] = 1;
for (int j = 1; j <= i; ++j) {
c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % mod;
}
}
f[1][n] = f[1][n - 1] = n;
for (int i = 1; i <= n; ++i) {
for (int j = -n; j <= n; ++j) {
if (f[i][j + n]) {
for (int k = max(1, abs(j)); k <= n - i; ++k) {
if (!(j + k & 1)) {
for (int l = 0; l <= k; ++l) {
int t = (j + k >> 1) - l;
if (t >= -n && t <= n) {
f[i + k][t + n] = (1LL * f[i][j + n] * c[n - i][k] % mod * c[k][l] + f[i + k][t + n]) % mod;
}
}
}
}
}
}
}
printf("%d\n", f[n][n]);
#ifdef wxh010910
Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
return 0;
}
本文提供了五道算法竞赛题目的详细解答过程,包括字符串处理、序列构造、动态规划等核心内容,通过具体实现展示了高效的算法设计技巧。

被折叠的 条评论
为什么被折叠?



