ABC243
ABC224
D
题目大意
有一个九个点的无向图棋盘,上面有八个棋子,一次操作能将一个棋子沿边移到空点上,问将每个棋子移到与它编号相同的点最少几步。
解题思路
考虑使用 BFS。
用 string
存储状态,
注意:一开始不能直接修改 000000000
。
利用 unordered_map
判断此状态是否访问过,用 map
会 TLE。
每次找到字符串中的
如果找到状态为 123456780
,就输出答案,没有说明无解,输出
代码
#include<bits/stdc++.h>
#define endl "\n"
using namespace std;
const int N = 40;
struct edge
{
int to, next;
} e[N << 1];
int m, tot;
int h[20];
string s = " 000000000";
queue<pair<string, int> > q;
unordered_map<string, int> mp;
void add(int u, int v)
{
tot++;
e[tot].to = v;
e[tot].next = h[u];
h[u] = tot;
}
int main()
{
ios :: sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> m;
for (int i = 1; i <= m; i++)
{
int u, v;
cin >> u >> v;
add(u, v), add(v, u);
}
for (int i = 1; i <= 8; i++)
{
int x;
cin >> x;
s[x] = '0' + i;
}
q.push(make_pair(s, 0));
mp[s] = 1;
while (!q.empty())
{
s = q.front().first;
int x = q.front().second;
q.pop();
if (s == " 123456780")
{
cout << x << endl;
return 0;
}
int u = s.find("0");
for (int i = h[u]; i; i = e[i].next)
{
int v = e[i].to;
swap(s[u], s[v]);
if (!mp.count(s))
{
q.push(make_pair(s, x + 1));
mp[s] = 1;
}
swap(s[u], s[v]);
}
}
cout << -1 << endl;
return 0;
}
E
题目大意
给出一个矩形,上面有一些点上有数
解题思路
考虑将所有点建图,每个数只能变大,说明这是一个 DAG。
因此,我们考虑使用 DAG 上 dp。
但在编码时可以不用建图,减少编码难度。
发现当这个数在当前行和当前列都为最大时一步都走不了,因此可以以这些状态为初始,然后逐步更新相邻点,也就是将这个过程倒过来看,由大数往小数跳。
所以可以将所有点按
我们定义
每遍历到一个点,就有转移方程:
特别地,如果当前行或列最大值还没有被更新,可以将其初始化为
但是我们考虑到会有重复值,便不能从当前行最大值转移,因此上面算法并不完全正确。
由于我们遍历从大到小,因此如果和最小的
因此我们只要再存储次小的
转移时如果
时间复杂度
代码
#include<bits/stdc++.h>
#define endl "\n"
#define ll long long
using namespace std;
const int N = 2e5 + 10;
struct node
{
int x, y, w, id;
} q[N];
int h, w, n, tot;
int a[N][2], b[N][2], c[N][2], d[N][2], dp[N];
bool cmp(node x, node y)
{
return x.w < y.w;
}
int main()
{
ios :: sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> h >> w >> n;
for (int i = 1; i <= n; i++)
{
cin >> q[i].x >> q[i].y >> q[i].w;
q[i].id = i;
}
sort(q + 1, q + n + 1, cmp);
memset(a, -1, sizeof a);
memset(b, -1, sizeof b);
memset(c, 0x7f, sizeof c);
memset(d, 0x7f, sizeof d);
for (int i = n; i >= 1; i--)
{
if (q[i].w < c[q[i].x][0])
{
dp[q[i].id] = a[q[i].x][0] + 1;
c[q[i].x][1] = c[q[i].x][0];
c[q[i].x][0] = q[i].w;
a[q[i].x][1] = a[q[i].x][0];
}
else
{
dp[q[i].id] = a[q[i].x][1] + 1;
}
if (q[i].w < d[q[i].y][0])
{
dp[q[i].id] = max(dp[q[i].id], b[q[i].y][0] + 1);
d[q[i].y][1] = d[q[i].y][0];
d[q[i].y][0] = q[i].w;
b[q[i].y][1] = b[q[i].y][0];
}
else
{
dp[q[i].id] = max(dp[q[i].id], b[q[i].y][1] + 1);
}
a[q[i].x][0] = max(a[q[i].x][0], dp[q[i].id]);
b[q[i].y][0] = max(b[q[i].y][0], dp[q[i].id]);
}
for (int i = 1; i <= n; i++)
{
cout << dp[i] << endl;
}
return 0;
}
F
题目大意
给出一个大整数,可以往其中任意添加加号(可以不加),变成一个加法算式,问所有这种加法算式结果之和。
解题思路
考虑拆贡献。
设长度为
- 考虑后面的加号影响:
设此时第 位是 位数,那么一种情况会有 的贡献,后面最左的加号在第 位,后面有 位可以随便填,那么有 种情况,特别地,如果后面没有加号,有 种情况。
那么求和就能得到以下式子:不难得到递推式: - 考虑前面的加号影响:
只需考虑情况数即可,为 。
最后只要拿当前位的数乘上两个影响即可得到当前位贡献,最后求和。
代码实现可以预处理
代码
#include<bits/stdc++.h>
#define endl "\n"
#define ll long long
using namespace std;
const int N = 2e5 + 10, P = 998244353;
ll n, ans;
ll f[N], g[N];
string s;
int main()
{
ios :: sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> s;
n = s.length();
s = " " + s;
g[0] = 1;
for (int i = 1; i <= n; i++)
{
g[i] = (2 * g[i - 1]) % P;
}
f[n] = 1;
for (int i = n - 1; i >= 1; i--)
{
(f[i] = f[i + 1] * 10 + g[n - 1 - i]) %= P;
}
for (int i = 1; i <= n; i++)
{
(ans += (s[i] - '0') * g[i - 1] * f[i]) %= P;
}
cout << ans << endl;
return 0;
}
G
题目大意
一个骰子,有两种操作:
- 支付
元,使掷出的点数 ,但不能超过 。 - 支付
元,掷一次骰子,使点数以相等概率随机变为 到 之间的整数。
一开始点数为
解题思路
首先先讨论不掷骰子只加点数的情况,当
然后考虑要掷骰子,重掷骰子后加的点数就会无效,因此一定是在掷多次后,到达一个离
不妨设一个阈值
于是我们就可以将策略分为两部分:
- 掷骰子
掷一次骰子,随机到 之间的概率为 。
根据伯努利过程的结论,次数的期望就是概率的倒数,为 ,因此此过程花费的期望 。 - 加点数
掷出 中 的概率为 ,这个点走到 需要 次操作,那么它到 花费的期望就为 。
将其中所有点数的期望求和,化简得 。
根据期望的线性性质,全过程的期望即为
再根据均值不等式:
因此取
值得注意的是,如果取不到函数极值那么函数单调,需要取边界值
代码
#include<bits/stdc++.h>
#define endl "\n"
using namespace std;
long long n, s, t, a, b;
long double ans;
inline long double get(int x)
{
return 1.0 * b * n / x + a * (x - 1) / 2.0;
}
int main()
{
ios :: sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> s >> t >> a >> b;
if (s == t)
{
cout << 0 << endl;
return 0;
}
ans = 1.0 * b * n;
if (s < t)
{
ans = min(ans, (long double)(t - s) * a);
}
ans = min(ans, min(get(1), get(t)));
long long x = sqrtl(2.0 * b * n / a);
if (x <= t)
{
ans = min(ans, get(x));
if (x >= 1)
{
ans = min(ans, get(x - 1));
}
if (x <= t)
{
ans = min(ans, get(x + 1));
}
}
cout << ans << endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)