A
首先交换两个位置上的数并不会影响两个数的和。
所以用基本不等式可以得出当两个数一个最小一个最大时乘积就最小。
然后考虑怎么算高精度乘法。
因为要取模,所以我们不用 FFT 啥的,只要按位乘就好了。
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
const ll MOD = 998244353;
char a[N], b[N];
int n;
int main() {
scanf("%d%s%s", &n, a + 1, b + 1);
for (int i = 1; i <= n; i ++) if (a[i] > b[i]) swap(a[i], b[i]);
ll mul = 1, sumb = 0;
for (int i = n; i >= 1; i --) sumb = (mul * (b[i] - '0') % MOD + sumb) % MOD, mul = mul * 10 % MOD;
mul = 1;
ll ans = 0;
for (int i = n; i >= 1; i --) ans = (ans + mul * (a[i] - '0') % MOD * sumb % MOD) % MOD, mul = mul * 10 % MOD;
printf("%lld\n", ans);
return 0;
}
B
首先不难发现如果两个字符串本质相同(组成的字符相同),那么就一定能通过若干次操作得到 B 串。
然后不难发现最长能够保留的字符串的长度应该是 A 的一个为 B 的子串的最长后缀。
然后我们设计一个 dp。
\(f_i\) 表示最长能够匹配的后缀长度,然后前缀和优化下,就做完了。
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 2e5 + 10;
int n, cnt[2][26], f[N], g[26];
char a[N], b[N];
int main() {
scanf("%d%s%s", &n, a + 1, b + 1);
for (int i = 1; i <= n; i ++) cnt[0][a[i] - 'a'] ++;
for (int i = 1; i <= n; i ++) cnt[1][b[i] - 'a'] ++;
for (int i = 0; i < 26; i ++) if (cnt[0][i] != cnt[1][i]) return puts("-1"), 0;
int l = 1, r = n, ans = 0;
for (int i = 0; i < 26; i ++) g[i] = n + 100;
for (int i = 1; i <= n; i ++) f[i] = n + 1;
g[a[n] - 'a'] = n;
int minLen = n + 1;
for (int i = n; i >= 1; i --) {
f[i] = min(f[i], g[b[i] - 'a']);
minLen = min(minLen, f[i]);
if (f[i] > 1) {
int nxt = a[f[i] - 1] - 'a';
g[nxt] = min(g[nxt], f[i] - 1);
}
}
printf("%d\n", minLen - 1);
return 0;
}
C
D
注意到,如果我们找出了 \(1\) 的位置,那么我们其实就可以比两个数的大小了。
假设我们要比较 \(A, B\) 的大小。
因为 \(A \not = B\),所以 \(A > B\) 当且仅当 \(A + 1 > B\)。
正确性显然。
所以如果我们求出了 \(1\) 的位置,那我们就可以通过排序来求出原序列了,非常方便。
接下来考虑如何求出 \(1\) 的位置。
首先注意到 \(1 + 1\) 不大于任何数,所以我们就可以这样找 \(1\)。
假设我们当前找到的最小的数为 \(x\)。
然后我们将 \(i = 1,2,3,\dots,n\),询问 \(p_x + p_x\) 与 \(p_i\) 的关系。
如果大于那么就 \(x = i\)。
因为 \(i\) 一定会遍历到 \(1\) 的位置,且条件一定成立,所以 \(x\) 最后一定会为 \(1\) 的位置。
那么这题就做完了,个人感觉比 C 简单。
需要注意的一点是这题卡快排,或者可能是我比较 low iq。
#include <cstdio>
#include <vector>
#include <algorithm>
#include <numeric>
using namespace std;
int n;
char s[10000];
bool ask(int i, int j, int k) {
printf("? %d %d %d\n", i, j, k);
fflush(stdout);
scanf("%s", s + 1);
return s[1] == 'Y';
}
void merge_sort(vector<int> &arr, const function<bool(int, int)> &cmp) {
int len = arr.size();
if (len == 1) return;
vector<int> a, b;
for (int i = 0; i < len; i ++) if (i * 2 < len) a.push_back(arr[i]); else b.push_back(arr[i]);
merge_sort(a, cmp), merge_sort(b, cmp);
vector<int> res;
int i = 0, j = 0;
while (i + j < len) {
if (i < a.size() && j < b.size()) {
if (cmp(a[i], b[j])) res.push_back(a[i ++]);
else res.push_back(b[j ++]);
} else if (i < a.size()) {
res.push_back(a[i ++]);
} else {
res.push_back(b[j ++]);
}
}
swap(arr, res);
}
int main() {
scanf("%d", &n);
int pos1 = 1;
for (int i = 2; i <= n; i ++) if (ask(pos1, pos1, i)) pos1 = i;
vector<int> c(n);
iota(c.begin(), c.end(), 1);
merge_sort(c, [&](int x, int y) { return !ask(x, pos1, y); });
vector<int> ans(n + 1);
for (int i = 0; i < n; i ++) ans[c[i]] = i + 1;
printf("! ");
for (int i = 1; i <= n; i ++) printf("%d%c", ans[i], " \n"[i == n]);
return 0;
}