2022 ICPC 47 合肥 AHGB(JM)

(前几天连续几天只睡了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题,之后有缘再回来补这题
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值