专栏文章
【RS十周年】比赛题解
算法·理论参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mio3fc7u
- 此快照首次捕获于
- 2025/12/02 12:43 3 个月前
- 此快照最后确认于
- 2025/12/02 12:43 3 个月前
Successful person
优先用大盒:先看 n 能否被 5 整除,若能,用 5 颗装盒子数最少,结果为 n / 5。
混合装尝试:若不能被 5 整除,看余数能否被 3 整除,能则用 5 颗装和 3 颗装组合。
逐步减 3 尝试:若上述都不满足,不断从 n 中减 3,每减一次检查剩余数量能否被 5 整除,能则计算总盒数。
若整个过程都没找到方案,输出 wwyytsn!,否则输出最少盒子数。
CPP混合装尝试:若不能被 5 整除,看余数能否被 3 整除,能则用 5 颗装和 3 颗装组合。
逐步减 3 尝试:若上述都不满足,不断从 n 中减 3,每减一次检查剩余数量能否被 5 整除,能则计算总盒数。
若整个过程都没找到方案,输出 wwyytsn!,否则输出最少盒子数。
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
int result = -1;
if (n % 5 == 0) {
result = n / 5;
} else if ((n % 5) % 3 == 0) {
result = n / 5 + (n % 5) / 3;
} else {
int temp = n;
while (temp >= 3) {
temp -= 3;
if (temp % 5 == 0) {
result = temp / 5 + (n - temp) / 3;
break;
}
}
}
if (result == -1) {
cout << "wwyytsn!";
} else {
cout << result;
}
return 0;
}
迷魂阵
(本来有个更难的小模拟的,但是后面题有点爆了,所以这题想着节省一点时间的)
每个棋子走到对面需要 步数,所以至少需要 步。如果某一列的黑子和白子同时向他们的正方向移动,那么会相撞。不妨让黑子在原来的列,白子进行交错。考虑第 列的白子最后走到了第 列,那么m多出来步数为
由于 ,该和式存在下界可以对相邻的两列 ,,当 是偶数时这样直
接可以取到下界,而 是奇数时,只需要前三列 即可,刚好满足下界。
代码1
CPP#include <bits/stdc++.h>
using namespace std;
int main() {
long long n;
cin >> n;
long long ans = n * (2 * n - 1);
if (n & 1) cout << ans + 1 << endl;
else cout << ans << endl;
return 0;
}
代码2
CPP#include <bits/stdc++.h>
#define LL long long
using namespace std;
LL n;
int main() {
cin >> n;
cout << 2 * n * (n - 1) + n + (n % 2);
return 0;
}
地心历险
算法一
注意到图是三部图,如果令 就复合条件了。图的性质不太好,先研究树的情况。
对于一个非根节点,显然可以通过父亲边调整权值。设 ,那么如果我们可以找到包含根的一个奇环,我们不断在上面 ,与根相连的两条边都是 ,这样相当于 。而其他点都不变,也就满足了条件。于是当这个图不是二分图时,找一个奇环上的点做根 即可。
接下来考虑二分图的情况,重新给图染色(只用 )。不妨令根的颜色为 ,这样只有当最后算出情况 是 的时候才会出错。可我们发现 这种点权还没用,这时我们不妨选两条边给其加 ,容易发现这时 并没有什么问题。可以选择度数大于 的点当根。
对于一个非根节点,显然可以通过父亲边调整权值。设 ,那么如果我们可以找到包含根的一个奇环,我们不断在上面 ,与根相连的两条边都是 ,这样相当于 。而其他点都不变,也就满足了条件。于是当这个图不是二分图时,找一个奇环上的点做根 即可。
接下来考虑二分图的情况,重新给图染色(只用 )。不妨令根的颜色为 ,这样只有当最后算出情况 是 的时候才会出错。可我们发现 这种点权还没用,这时我们不妨选两条边给其加 ,容易发现这时 并没有什么问题。可以选择度数大于 的点当根。
算法二
上述算法中直接构造只有根可能出错,故当根不合法时,重新随机选择根和 dfs 生成树。注意到题目只要求值不同而不是上面提到的模 与 相同,故随意调整几次即可满足条件。
CPP#include <bits/stdc++.h>
#define pb push_back
#define pf push_front
#define mp make_pair
using namespace std;
template <typename T>
void read(T &x) {
T flag = 1;
char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') flag = -1;
for (x = 0; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
x *= flag;
}
const int maxn = 200005;
struct e{
int u, v, val;
}ans[maxn];
int n, m;
char s[maxn];
int col[maxn], f[maxn], val[maxn], d[maxn];
vector<pair<int, int>> vec[maxn], t[maxn];
bool vis[maxn];
int tmp[maxn];
int flag, End;
int pre[maxn], num[maxn];
void dfs(int x, int fa, int id) {
f[x] = fa;
if (fa) t[x].pb(mp(fa, id));
for (int i = 0; i < (int)vec[x].size(); i++) {
int y = vec[x][i].first;
if (f[y] > 0 || y == flag) continue;
t[x].pb(mp(y, vec[x][i].second));
dfs(y, x, vec[x][i].second);
}
}
void get_ans(int x) {
for (int i = 0; i < (int)t[x].size(); i++) {
int y = t[x][i].first;
if (y == f[x]) continue;
get_ans(y);
int m = col[y] - d[y];
ans[t[x][i].second].val = m;
d[y] = d[y] + m;
d[x] = d[x] + m;
}
}
void get_ans2(int x) {
for (int i = 0; i < (int)t[x].size(); i++) {
int y = t[x][i].first;
if (y == f[x]) continue;
get_ans2(y);
int m = tmp[y] - d[y];
ans[t[x][i].second].val = m;
d[y] = d[y] + m;
d[x] = d[x] + m;
}
}
void check(int x) {
for (int i = 0; i < (int)vec[x].size(); i++) {
int y = vec[x][i].first;
if (tmp[y] == -1) tmp[y] = tmp[x] ^ 1, check(y);
else {
if (tmp[y] == tmp[x]) {
flag = x;// 不是二分图
}
}
}
}
void yyy(int x) {
for (int i =0; i < (int)vec[x].size(); i++) {
int y = vec[x][i].first;
if (tmp[y] != -1) continue;
tmp[y] = tmp[x] ^ 1;
yyy(y);
}
}
int cnt[maxn];
void output() {
for (int i = 1; i <= m; i++) {
ans[i].val = (ans[i].val % 3 + 3) % 3;
if (ans[i].val == 0) ans[i].val = 3;
printf("%d\n", ans[i].val);
cnt[ans[i].u] += ans[i].val;
cnt[ans[i].v] += ans[i].val;
}
}
void jjj(int x) {
for (int i = 0; i < (int)vec[x].size(); i++) {
int y = vec[x][i].first;
if (tmp[y] == -1) tmp[y] = tmp[x] ^ 1, pre[y] = x, num[y] = vec[x][i].second, jjj(y);
else {
if (y == flag && tmp[x] == tmp[flag]) {
End = x;
}
}
}
}
void work() {
tmp[1] = 0;
check(1);
if (flag) {// 不是二分图
dfs(flag, 0, 0);
get_ans(flag);
int m = (col[flag] - d[flag]);
memset(tmp, -1, sizeof(tmp));
tmp[flag] = 0;
jjj(flag);
for (int i = End; i != flag; i = pre[i]) {
ans[num[i]].val += m;
m = -m;
}
for (int i = 0; i < (int)vec[End].size(); i++) {
if (vec[End][i].first == flag) ans[vec[End][i].second].val += m << 1;
}
output();
} else {
flag = 1;
memset(tmp, -1, sizeof(tmp));
tmp[1] = 0;
yyy(flag);
dfs(flag, 0, 0);
get_ans2(flag);
if ((d[1] % 3 + 3) % 3 == 1 && vec[1].size() > 1) {
ans[vec[1][1].second].val++; ans[vec[1][2].second].val++;
}
output();
}
}
int main() {
memset(tmp, -1, sizeof(tmp));
read(n); read(m);
for (int i = 1; i <= n; i++) {
read(col[i]);
}
for (int i = 1; i <= m; i++) {
int u, v;
read(u); read(v);
ans[i].u = u; ans[i].v = v;
vec[u].pb(mp(v, i));
vec[v].pb(mp(u, i));
}
for (int i = 1; i <= n; i++) reverse(vec[i].begin(), vec[i].end());
work();
return 0;
}
魔法屋
发现 并不会改变
的值。记 ,于是可以分成两个部分, 和 , 前者在操作的过程中不会变,总共会对答案有 的贡献,后者较小,考虑动态规划。
记 代表值为 的数,第 次操作开始,后面对答案的总贡献。转移分成两部分,如果当前选中这个数,则从 转移,否则以 系数从 转移。即
其中 代表方案数,是辅助数组。转移即为
而答案即为 。注意到修改只是修改一个位置,那么其对答案的贡献可以 表示,那么就做到了 修改。有一些 dp 的做法可能无法做到 修改,可惜hxydz太懒了脑子不够用了。
CPP#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e7 + 5, mod = 1e9 + 7;
template <typename T>
void read(T &x) {
T sgn = 1;
char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1;
for (x = 0; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
x *= sgn;
}
int n, a[maxn], x, y, k, m, ans, cnt[maxn];
int f[20][720721], g[20][720721], pw[20], q;
int qmod(int x) { return x >= mod ? x - mod : x; }
int ksm(int a, int b = mod - 2) { int ret = 1; for (; b; b >>= 1, a = 1ll * a * a % mod) if (b & 1) ret = 1ll * ret * a % mod; return ret; }
int main() {
int lcm = 1;
for (int i = 1; i <= 16; i++) lcm = lcm * i / __gcd(lcm, i);
read(n); read(k);
for (int i = 1; i <= n; i++) read(a[i]);
pw[0] = 1;
for (int i = 1; i <= k; i++) pw[i] = 1ll * pw[i - 1] * n % mod;
for (int i = 1; i <= n; i++)
cnt[a[i] % lcm]++, ans = qmod(ans + 1ll * (a[i] / lcm * lcm) * pw[k - 1] % mod * k % mod);
for (int i = 0; i < lcm; i++) g[k + 1][i] = 1;
for (int i = k; i; i--)
{
for (int j = 0; j < lcm; j++)
{
f[i][j] = qmod(1ll * (n - 1) * f[i + 1][j] % mod + f[i][j]);
f[i][j] = qmod(qmod(1ll * j * g[i + 1][j - j % i] % mod + f[i + 1][j - j % i]) + f[i][j]);
g[i][j] = qmod(1ll * (n - 1) * g[i + 1][j] % mod + g[i + 1][j - j % i]);
}
}
for (int i = 0; i < lcm; i++) ans = qmod(ans + 1ll * cnt[i] * f[1][i] % mod);
printf("%d\n", ans);
read(q);
while (q--) {
int x, y;
read(x); read(y);
ans = qmod(ans - 1ll * (a[x] / lcm * lcm) * pw[k - 1] % mod * k % mod + mod);
ans = qmod(ans - f[1][a[x] % lcm] + mod);
a[x] = y;
ans = qmod(ans + 1ll * (a[x] / lcm * lcm) * pw[k - 1] % mod * k % mod);
ans = qmod(ans + f[1][a[x] % lcm]);
printf("%d\n", ans);
}
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...