(前几天连续几天只睡了3、4个小时 有点头疼 简单写下题解记录下这一场)
8题金 6题银 4题铜
到比赛那天衣服也还没寄到 难受 看群里的照片挺好看的 还蛮期待的来着
赛前一天,队友*1参加这一站的什么活动,抽了个蓝牙音响
“完了,欧气提前一天用完了”
上一次是差点银,这一次确实是还差好多才能银,只拿了个铜。(也许再加一个音响?)
只学了一年,学的算法还是太少了,还不够稳拿银。
A. Welcome to USTC
签到题
题意:
给一个小写字符串,里面混入了一个U一个S一个T一个C,保证相对位置是USTC
每次操作可以交换两个相邻的字符
问至少多少次操作把USTC放到一起
解法:
最暴力的解法,枚举每个点作为U,然后把其他的操作过来,比较所有情况中最优的操作次数。
(吸取上一场C题教训,直接考虑所有情况,复杂度允许下最保险的写法)
核心代码:
char st[MXN];
void Solve(void)
{
cin >> (st + 1);
int len = strlen(st + 1);
int u, s, t, c;
FOR(i, 1, len)
{
if (st[i] == 'U')
u = i;
if (st[i] == 'S')
s = i;
if (st[i] == 'T')
t = i;
if (st[i] == 'C')
c = i;
}
int ans = MXN;
FOR(i, 1, len - 3)
{
int tmp1 = u - i;
int tmp2 = s - i - 1;
int tmp3 = t - i - 2;
int tmp4 = c - i - 3;
if (tmp1 < 0)
tmp1 = -tmp1;
if (tmp2 < 0)
tmp2 = -tmp2;
if (tmp3 < 0)
tmp3 = -tmp3;
if (tmp4 < 0)
tmp4 = -tmp4;
int res = tmp1 + tmp2 + tmp3 + tmp4;
ans = min(ans, res);
}
cout << ans << edl;
H. Jackpot
题意:
有n个龙,龙这一种前面有k种东西,k种中第一种是熊猫
每次操作,会有一个从当前种类变成排在前面的种类,变成的概率是均等的
就是说 比如第四种有1/3的概率变为第一种/第二种/第三种其中一种
之后还会继续操作 直到变为1号熊猫
问把n个龙都变为熊猫的最少操作次数的期望
题解:
推出式子后预处理下逆元然后n^2预处理好每一种k的期望
(因为平常直接用代码片段补全导致比赛的时候逆元和取模写特别慢...)
核心代码:
ll KSM(ll base, long long exp)
{
// assert(exp>=0);
base %= MOD;
ll res = 1;
while (exp)
{
if (exp & 1)
{
res *= base;
res %= MOD;
}
base *= base;
base %= MOD;
exp >>= 1;
}
return res;
}
ll n, k;
ll inv[MXN];
ll e[MXN];
ll ans;
void Init(int N)
{
ROF(i, N + 2, 0)
inv[i] = KSM(i, MOD - 2);
e[1] = 0;
e[2] = 1;
FOR(i, 3, N)
FOR(j, 1, i - 1)
{
e[i] += (inv[i - 1] * ((e[j] + 1) % MOD)) % MOD;
e[i] %= MOD;
}
return;
}
void Solve(void)
{
cin >> n >> k;
ans = (e[k + 1] * n) % MOD;
cout << ans << edl;
return;
}
int main(void)
{
std::ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
Init(MXN - 3);
int t;
cin >> t;
while (t--)
Solve();
return 0;
}
G. Game Plan
题意:
好像是给t组数,每组两个数,只选其中一个,然后求选出的数的MEX?
(虽然最后的代码是我调的,并查集和离散化什么的也都是我改的加的,但在被叫去调bug前一直在做B。所以实际上题都还没读过...听*1大致说了下题目和算法然后改了几个明显的bug,改了下并查集,加了个离散化,之后*1和xy一起帮忙看着改了点细节就过了...感觉非常神奇,到AC我都没读过题,全靠*1的描述来想象)
题解:
大概是连通块离散化后处理一下?应该?
核心代码:
constexpr int N = 2e6 + 10;
int fa[N];
bool vis[N];
vector<int> g[N];
set<int> st;
vector<ll> ve;
//
int uu[MXN];
int vv[MXN];
int GetID(int v) { return lower_bound(ve.begin(), ve.end(), v) - ve.begin() + 1; }
int GetV(int id) { return ve[id - 1]; }
int find(int x) { return (x == fa[x]) ? x : fa[x] = find(fa[x]); }
void Solve(void)
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= 2e6 + 5; i++)
fa[i] = i;
//
FOR(i, 1, m)
{
cin >> uu[i] >> vv[i];
ve.push_back(uu[i]);
ve.push_back(vv[i]);
}
sort(ve.begin(), ve.end());
ve.erase(unique(ve.begin(), ve.end()), ve.end());
for (int i = 1; i <= m; i++)
{
int u, v;
u = GetID(uu[i]);
v = GetID(vv[i]);
if (u > v)
swap(u, v);
int pa = find(u), pb = find(v);
if (pa == pb)
vis[pa] = 1;
else
{
fa[pb] = pa;
if (vis[pb])
vis[pa] = 1;
}
}
for (int i = 1; i <= 2e6 + 5; i++)
{
g[find(i)].push_back(i);
st.insert(i);
}
for (int i = 1; i <= 2e6 + 5; i++)
{
if (vis[i])
for (auto j : g[i])
st.erase(GetV(j));
else
{
int p = g[i].size();
if (p == 0)
continue;
sort(g[i].begin(), g[i].end());
for (int j = 0; j < p - 1; j++)
st.erase(GetV(g[i][j]));
}
}
cout << *st.begin();
return;
}
B. Genshin Impact
题意:
每次技能可以点燃敌人x秒,每y秒可以放一次技能,每次技能有1/p的几率命中
点燃是重置敌人的燃烧时间到x秒,而非增加燃烧时间
问给无限的时长一直连续的放技能,敌人燃烧时间占总时长的占比的期望。
解法:
x<=y的时候,显然期望为x/(y*p)
x>y的时候,反过来思考没有燃烧的概率和时长
核心代码:
ll x, y, p;
db t, f;
db ans;
void Solve(void)
{
cin >> x >> y >> p;
if (x <= y)
{
ans = x;
ans /= y * p;
cout << SPO(15) << ans << edl;
return;
}
t = 1.0;
t /= p;
f = 1.0 - t;
ans = 0.0;
db tmp = 1.0;
tmp /= p;
for (ll i = x; i >= 1; i--)
if ((x - i) % y == 0)
{
ans += tmp * min(y, i);
tmp *= f;
}
ans /= y;
cout << SPO(15) << ans << edl;
return;
}
J. Produce the Problems
题意:
有n个题,D类型知识点不能连续出现a次以上,C类型知识点不能连续b次以上。
d1 d2 ... dn,代表第i题需要用di次D知识点
c1 c2 ... cn,代表第i题需要用ci此C知识点
问能否找一种方法,把所有题搞定
连续两题的交接处的知识点也会连续
解法:
用f[1][i]表示第i题结尾最少是几个连续的c
用f[0[[i]表示第i题结尾最少是几个连续的d
根据i-1的两个状态可以推出i的两个状态
中途如果出现不合法的f1/f0 下一个的状态就不能用这个来转移
如果两个都不合法 那么输出0
否则中途没有输出0 最后就是1
要特判a b为0的情况
最后时间太紧了 写的很麻烦 比赛结束前6s赶着提交了上去 结果发现前面2k7份排队提交???
交上去后发现特判没有加上去...
可能加上特判也还有点问题,毕竟写法太麻烦了。最后1.5h同时开了JM两题,决定做J题的时候已经没多少时间了,这个转移也很难写,为了保险不漏情况写的太复杂了。
赛中没改对的代码:
// #define NDEBUG
#include <bits/stdc++.h>
using namespace std;
namespace AIN
{
using db = double;
using ll = long long;
#define edl '\n'
#define str string
#define pll pair<ll, ll>
#define fir first
#define sec second
#define heap priority_queue
#define SPO(n) fixed << setprecision(n)
#define FOR(i, l, r) for (auto i = l; i <= (r); ++i)
#define ROF(i, r, l) for (auto i = r; i >= (l); --i)
#ifdef debugcmd
#define DBG(n) cout << "!!! " << #n << ": " << n << edl
#else
#define DBG(n) ;
#endif
template <typename T>
T KSM(T base, long long exp)
{
// assert(exp>=0);
T res = 1;
while (exp)
{
if (exp & 1)
res *= base;
base *= base;
exp >>= 1;
}
return res;
}
// constexpr db PI = acos(-1.0);
// constexpr db EPS = 1.0e-9;
constexpr long long LNF = 0x3f3f3f3f3f3f3f3fLL;
constexpr int INF = 0x3f3f3f3f;
// constexpr long long MOD=998244353;
constexpr long long MOD = 1e9 + 7;
constexpr int MXN = 1e6 + 5;
}
using namespace AIN;
// a-d
// b-c
ll n, a, b;
ll d[MXN];
ll c[MXN];
// D/C 第i题结尾最少有几个连续
ll f[2][MXN];
void Solve(void)
{
cin >> n >> a >> b;
FOR(i, 1, n)
cin >> d[i];
FOR(i, 1, n)
cin >> c[i];
f[0][0] = 0;
f[1][0] = 0;
FOR(i, 1, n)
{
f[0][i] = f[1][i] = LNF;
ll n = d[i];
ll m = c[i];
ll k = min(n, m);
ll x = f[1][i - 1];
if (x <= b - 1)
{
if (n > m && k * a >= n)
{
f[1][i] = min(f[1][i], 0LL);
f[0][i] = min(f[0][i], max(0LL, n - (k - 1) * a));
}
if (n == m)
{
f[0][i] = min(f[0][i], 0LL);
f[1][i] = min(f[1][i], 1LL);
}
if (n < m && k * b + (b - x) >= m)
{
f[1][i] = min(f[1][i], max(0LL, m - ((k - 1) * b + (b - x))));
f[0][i] = min(f[0][i], 0LL);
}
}
if (x <= b)
{
if (n > m && (k + 1) * a >= n)
{
f[1][i] = min(f[1][i], 0LL);
f[0][i] = min(f[0][i], max(0LL, n - k - a));
}
if (n == m)
{
f[0][i] = min(f[0][i], 1LL);
f[1][i] = min(f[1][i], 0LL);
}
if (n < m && k * b + (b - x) >= m)
{
f[1][i] = min(f[1][i], max(0LL, m - ((k - 1) * b)));
f[0][i] = min(f[0][i], 0LL);
}
}
x = f[0][i - 1];
if (x <= a - 1)
{
if (n > m && (k + 1) * a >= n)
{
f[1][i] = min(f[1][i], 0LL);
f[0][i] = min(f[0][i], max(0LL, n - ((a - x) + (k - 1) * a)));
}
if (n == m)
{
f[1][i] = min(f[1][i], 1LL);
f[0][i] = min(f[0][i], 0LL);
}
if (n < m && k * b >= m)
{
f[1][i] = min(f[1][i], max(0LL, m - (k - 1) * b));
f[0][i] = min(f[0][i], 0LL);
}
}
if (x <= a)
{
if (n > m)
{
f[1][i] = min(f[1][i], 0LL);
f[0][i] = min(f[0][i], max(0LL, n - (k - 1) * a));
}
if (n == m)
{
f[1][i] = min(f[1][i], 0LL);
f[0][i] = min(f[0][i], 1LL);
}
if (n < m)
{
f[1][i] = min(f[1][i], max(0LL, m - k * b));
f[0][i] = min(f[0][i], 0LL);
}
}
}
if (f[0][n] == LNF && f[1][n] == LNF)
cout << 0 << edl;
else
cout << 1 << edl;
return;
}
int main(void)
{
std::ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
Solve();
return 0;
}
M. Mahjong
题意:
根据给的字符串ls
构造合法的s
答案不唯一
担心题意理解错,最后放掉了这题去做了J题,之后有缘再回来补这题