2024牛客寒假算法基础集训营3
A
void solve()
{
string s1, s2;
cin >> s1 >> s2;
int a = 0, b = 0;
if (s1[0] <= 'z' && s1[0] >= 'a')
a = s1[0] - 'a';
else
a = s1[0] - 'A';
if (s2[0] <= 'z' && s2[0] >= 'a')
b = s2[0] - 'a';
else
b = s2[0] - 'A';
cout << (a == b ? "Yes" : "No") << endl;
}
B
一定可以全消掉,所以答案只跟长度有关
void solve()
{
int n;
cin >> n;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++)
cin >> a[i];
cout << (n % 2 ? "qcjj" : "zn" )<< endl;
}
C
1.hash:
struct Hash
{
const int base1 = 1361, base2 = 1301;
const int p1 = 1000000123, p2 = 1000000021;
int n;
vector<int> a1, a2, c1, c2;
Hash(int _n) : n(_n), a1(n + 10), a2(n + 10), c1(n + 10, 0), c2(n + 10) {}
void build(int n, vector<char> arr)
{
ll res = 0;
c1[0] = 1, c2[0] = 1;
for (int i = 1; i <= n; i++)
{
res = (res * base1 + arr[i]) % p1;
c1[i] = 1ll * c1[i - 1] * base1 % p1;
a1[i] = res;
}
res = 0;
for (int i = 1; i <= n; i++)
{
res = (res * base2 + arr[i]) % p2;
c2[i] = 1ll * c2[i - 1] * base2 % p2;
a2[i] = res;
}
}
pii query(int l, int r) // 询问子串的哈希值
{
int hashval1 = (a1[r] - 1ll * a1[l - 1] * c1[r - l + 1] % p1 + p1) % p1;
int hashval2 = (a2[r] - 1ll * a2[l - 1] * c2[r - l + 1] % p2 + p2) % p2;
return {hashval1, hashval2};
}
};
void solve()
{
int n, m;
cin >> n >> m;
vector<char> s(n + 1), t(m + 1);
for (int i = 1; i <= n; i++)
cin >> s[i];
for (int i = 1; i <= m; i++)
cin >> t[i];
Hash hs(n), hrs(n), ht(m), hrt(m);
hs.build(n, s), ht.build(m, t);
reverse(s.begin() + 1, s.end());
reverse(t.begin() + 1, t.end());
hrs.build(n, s), hrt.build(m, t);
vector<int> ans1, ans2;
for (int i = 1; i <= min(n, m); i++)
if (hs.query(1, i) == hrs.query(n - i + 1, n) && ht.query(m - i + 1, m) == hrt.query(1, i))
if (hs.query(1, i) == ht.query(m - i + 1, m))
ans1.push_back(i);
for (int i = 1; i <= min(n, m); i++)
{
if (ht.query(1, i) == hrt.query(m - i + 1, m) && hs.query(n - i + 1, n) == hrs.query(1, i))
if (ht.query(1, i) == hs.query(n - i + 1, n))
ans2.push_back(i);
}
if (ans1.empty() || ans2.empty())
cout << "-1" << endl;
else
{
int res = 0;
for (auto i : ans1)
{
int l = 0, r = ans2.size() - 1;
while (l < r)
{
int mid = (l + r + 1) >> 1;
if (ans2[mid] + i <= n && ans2[mid] + i <= m)
l = mid;
else
r = mid - 1;
}
if (ans2[l] + i <= n && ans2[l] + i <= m)
res = max(res, (i + ans2[l]) * 2);
}
cout << res << endl;
}
}
2.kmp
3.manacher
4.exkmp
5.sa
D
预处理左右端点的最大字段和,枚举交换位置即可
void solve()
{
int n, k;
cin >> n >> k;
vector<ll> a(n + 1), dpl(n + 10, 0), dpr(n + 10, 0);
for (int i = 1; i <= n; i++)
cin >> a[i];
ll res = -1e18;
for (int i = 1; i <= n; i++)
{
dpl[i] = (dpl[i - 1] > 0 ? dpl[i - 1] + a[i] : a[i]);
res = max(res, dpl[i]);
}
for (int i = n; i >= 1; i--)
{
dpr[i] = (dpr[i + 1] > 0 ? dpr[i + 1] + a[i] : a[i]);
res = max(res, dpr[i]);
}
if (k)
{
for (int i = 1; i < n; i++)//i i+1
{
res = max(res, dpl[i - 1] + a[i + 1]);
res = max(res, dpr[i + 2] + a[i]);
}
}
cout << res << endl;
}
G/H
暴力枚举所有情况
void solve()
{
int n;
cin >> n;
vector<array<int, 3>> a(n);
vector<int> val(10, 0);
for (auto &[u, v, w] : a)
cin >> u >> v >> w;
bool ans = 0;
auto chk = [&]() -> bool
{
for (auto [u, v, w] : a)
{
int res = val[u] < val[v];
if (res != w)
return false;
}
return true;
};
for (int i = 1; i <= 3; i++)
for (int j = 1; j <= 3; j++)
for (int k = 1; k <= 3; k++)
{
val[1] = i, val[2] = j, val[3] = k;
ans |= chk();
}
cout << (ans ? "Yes" : "No") << endl;
}
J
处理出每个人被选中的概率,期望等于$\sum {p_i *1} $
void solve()
{
auto qmi = [&](ll a, ll b)
{
ll res = 1;
while (b)
{
if (b & 1)
res = res * a % mod;
b >>= 1;
a = a * a % mod;
}
return res;
};
int n, m, k;
cin >> n >> m >> k;
vector<vector<int>> e(n + m + 1);
vector<ll> d(n + m + 1, 1);
for (int i = 1; i <= k; i++)
{
int u, v;
cin >> u >> v;
v += n;
e[u].push_back(v), e[v].push_back(u);
}
for (int i = 1; i <= n + m; i++)
{
int sum = e[i].size();
if (sum)
{
ll p = qmi(sum, mod - 2);
p = (1 - p + mod) % mod;
for (auto to : e[i])
d[to] = (d[to] * p % mod) % mod;
}
}
for (int i = 1; i <= n + m; i++)
d[i] = (1 - d[i] + mod) % mod;
ll ans1 = 0, ans2 = 0;
for (int i = 1; i <= n; i++)
ans1 = (ans1 + d[i]) % mod;
for (int i = n + 1; i <= n + m; i++)
ans2 = (ans2 + d[i]) % mod;
cout << "modint" << endl;
cout << ans1 << " " << ans2 << endl;
}
K
每次暴力拓展红/黑节点即可
void solve()
{
int n, m, cnt = 1, sum;
cin >> n >> m;
sum = n + m;
vector<pii> ans(n + m + 1, {-1, -1});
if (!n)
{
cout << "No" << endl;
return;
}
n--;
vector<int> b, w;
b.push_back(1);
while (n > 0 || m > 0)
{
bool f = 0;
if (n > 0 && w.size())
{
f = 1;
n -= 2;
auto t = w.back();
w.pop_back();
ans[t] = {cnt + 1, cnt + 2};
cnt += 2;
b.push_back(ans[t].x), b.push_back(ans[t].y);
}
if (m > 0 && b.size())
{
f = 1;
m -= 2;
auto t = b.back();
b.pop_back();
ans[t] = {cnt + 1, cnt + 2};
cnt += 2;
w.push_back(ans[t].x), w.push_back(ans[t].y);
}
if (!f)
break;
}
if (n == 0 && m == 0)
{
cout << "Yes" << endl;
for (int i = 1; i <= sum; i++)
cout << ans[i].x << " " << ans[i].y << endl;
}
else
cout << "No" << endl;
}
L/M
dp
因为\((i,j),(j,i)\)是两种情况,所以要反转过来再来一遍
ll f[N][N]; // 接长度为i的后缀,mod36=j
void solve()
{
int n;
cin >> n;
map<ll, ll> mp;
vector<ll> a(n + 1);
for (int i = 1; i <= n; i++)
cin >> a[i];
auto cal = [&](ll x) -> int
{
int res = 0;
while (x > 0)
x /= 10, res++;
return res;
};
ll ans = 0;
for (int i = 1; i <= n; i++)
{
int len = cal(a[i]);
ans += f[len][(36 - a[i] % 36) % 36];
ll now = a[i] % 36;
for (int j = 1; j <= 18; j++)
{
now = now * 10 % 36;
f[j][now]++;
}
}
memset(f, 0, sizeof f);
reverse(a.begin() + 1, a.end());
for (int i = 1; i <= n; i++)
{
int len = cal(a[i]);
ans += f[len][(36 - a[i] % 36) % 36];
ll now = a[i] % 36;
for (int j = 1; j <= 18; j++)
{
now = now * 10 % 36;
f[j][now]++;
}
}
cout << ans << endl;
}