前言
题解
和初赛相比,题目质量和难度,还有数据强度明显增强。出的真不错,区分度很强。
码蹄杯平台对非c++还是不够友好T_T.
魔法占卜
难度: 白银
题型: 签到
双指针即可
#include<bits/stdc++.h>
using namespace std;
int main( )
{
string s;
string t;
cin >> s >> t;
function<bool()> check = [&]() {
int j = 0;
for (int i = 0; i < t.length(); i++) {
while (j < s.length() && t[i] != s[j]) {
j++;
}
if (j == s.length()) {
return false;
}
}
return true;
};
cout << (check() ? "Lucky!" : "QAQ Unlucky!") << endl;
return 0;
}
B. 魔法链路
难度: 黄金
思路: 拓扑排序
C. 魔法链路2
难度; 钻石
思路; 矩阵幂优化的DP
这种类型的矩阵幂还是第一次见,学习了。
D. 魔法天平
难度: 钻石
思路: 并查集 + 多重背包优化
- 题外话1 - 卡语言
c++可以借助bitset优化擦边过。
java二进制优化的多重背包被卡TLE,只有单调队列优化版本才行。
- 题外话2 - 数据弱
赛时好像放过了贪心解法,哭了。
二进制优化的多重背包
#include <bits/stdc++.h>
using namespace std;
class Dsu {
private:
std::vector<int> arr;
std::vector<int> gz;
public:
Dsu(int n) : arr(n + 1), gz(n + 1, 1) {}
int find(int x) {
if (arr[x] == 0) {
return x;
}
return arr[x] = find(arr[x]);
}
void merge(int x, int y) {
int a = find(x);
int b = find(y);
if (a != b) {
arr[a] = b;
gz[b] += gz[a];
}
}
int group(int x) {
return gz[find(x)];
}
};
int main() {
int n, m;
cin >> n >> m;
Dsu dsu(n);
for (int i = 0; i < m; ++i) {
int u, v;
cin >> u >> v;
dsu.merge(u, v);
}
std::map<int, int> gp;
for (int i = 1; i <= n; ++i) {
if (dsu.find(i) == i) {
gp[dsu.group(i)]++;
}
}
int mz = n / 2;
std::vector<bool> dp(mz + 1, false);
dp[0] = true;
for (const auto& [k, cnt] : gp) {
int acc = 0;
for (int i = 0; acc + (1 << i) <= cnt; ++i) {
for (int j = mz; j >= (1 << i) * k; --j) {
if (dp[j - (1 << i) * k]) {
dp[j] = true;
}
}
acc += (1 << i);
}
int left = cnt - acc;
if (left > 0) {
for (int j = mz; j >= left * k; --j) {
if (dp[j - left * k]) {
dp[j] = true;
}
}
}
}
long long ans = 0;
for (int i = mz; i >= 0; --i) {
if (dp[i]) {
ans = static_cast<long long>(i) * (n - i);
break;
}
}
std::cout << ans << std::endl;
return 0;
}
E. 魔法合并
难度: 星耀
思路:质数筛 + 树状数组
还是卡java,气炸,换c++秒过
#include <bits/stdc++.h>
using namespace std;
struct BIT {
BIT(int n) : n(n), arr(n + 1) {}
int query(int p) {
int r = 0;
while (p > 0) {
r += arr[p];
p -= p & -p;
}
return r;
}
void update(int p, int d) {
while (p <= n) {
arr[p] += d;
p += p & -p;
}
}
int n;
vector<int> arr;
};
int64_t ksm(int64_t b, int64_t v, int64_t mod) {
int64_t r = 1;
while (v > 0) {
if (v % 2==1) {
r = r * b % mod;
}
b = b * b % mod;
v /= 2;
}
return r;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
vector<int> primes;
vector<vector<array<int, 2>>> g(101);
for (int i = 1; i <= 100; i++) {
int v = i;
for (int j = 2; j <= v; j++) {
if (v % j == 0) {
int c = 0;
while (v % j == 0) {
c++;
v /= j;
}
g[i].push_back({j, c});
}
}
if (g[i].size() == 1 && g[i][0][1] == 1) primes.push_back(i);
}
int n;
cin >> n;
vector<BIT> bits(100, BIT(n));
vector<int> arr(n + 1);
for (int i = 1; i <= n; i++) {
cin >> arr[i];
auto &lst = g[arr[i]];
for (auto &[k, v] : lst) {
bits[k].update(i, v);
}
}
int64_t mod = (int64_t)1e9 + 7;
int q;
cin >> q;
while (q-- > 0) {
int op, l, r;
cin >> op >> l >> r;
if (op == 1) {
int64_t res = 1l;
for (int v: primes) {
int u = bits[v].query(r) - bits[v].query(l - 1);
int64_t p = ksm(v, u + 1, mod);
p = (p - 1 + mod) % mod;
int64_t inv = ksm(v - 1, mod - 2, mod);
p = p * inv % mod;
res = p * res % mod;
}
cout << res << '\n';
} else {
auto &lst = g[arr[l]];
for (auto &[k, v] : lst) {
bits[k].update(l, -v);
}
arr[l] = r;
auto &lst2 = g[arr[l]];
for (auto &[k, v] : lst2) {
bits[k].update(l, v);
}
}
}
return 0;
}
F. 魔法合并2
难度: 星耀
思路: 线段树
这题,好像lc周赛考过一次
G. 魔法徽章
难度: 星耀
思路: 根号分治 + 无向图有向化
#include<bits/stdc++.h>
using namespace std;
int main( )
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int n, m;
cin >> n >> m;
vector<vector<int>> g(n);
vector<int> deg(n);
vector<array<int, 2>> es;
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
u--; v--;
deg[u]++;
deg[v]++;
es.push_back({u, v});
}
for (auto &e: es) {
int u = e[0], v = e[1];
if (deg[u] < deg[v] || (deg[u] == deg[v] && u < v)) {
g[u].push_back(v);
} else {
g[v].push_back(u);
}
}
long long mod = (long long)1e9 + 7;
long long ans = 0;
for (int i = 0; i < n; i++) {
long long d = deg[i];
if (d >= 2) {
ans += d * (d - 1) / 2 * (d - 2) / 3 % mod;
ans %= mod;
}
}
for (auto &e: es) {
int u = e[0], v = e[1];
ans += (deg[u] - 1) * (deg[v] - 1) % mod;
ans %= mod;
}
// 转DAG
vector<bool> vis(n);
long long tot = 0;
for (int i = 0; i < n; i++) {
for (int u: g[i]) vis[u] = true;
for (int u: g[i]) {
for (int v: g[u]) {
if (vis[v]) tot++;
}
}
for (int u: g[i]) vis[u] = false;
}
ans = ((ans - tot * 2) % mod + mod) % mod;
cout << ans << '\n';
return 0;
}
H. 魔法修路
难度: 星耀
思路; 并查集 + lca
I. 魔法编程
难度: 王者
J. 魔法咒语
难度: 王者
K. 魔法少女小码妹外传之与小码哥的决斗
难度: 黄金
题型: 签到
模拟即可,但是需要加速收敛