2024.2.13 寒假训练记录(23)

文章目录

  • ATC abc340C Divide and Divide
  • ATC abc340D Super Takahashi Bros.
  • ATC abc340E Mancala 2
  • ATC abc340F S = 1
  • ATC abc338F Negative Traveling Salesman
  • ATC abc337C Lining Up 2
  • ATC abc337D Cheating Gomoku Narabe

ATC abc340C Divide and Divide

题目链接

用优先队列模拟一下,需要注意要用map存储一下每个数字出现的次数进行优化,否则会t

#include 

using namespace std;

#define int long long
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;

const int N = 2e5 + 10;
const int mod = 1e9 + 7;
const int mod1 = 954169327;
const int mod2 = 906097321;

void solve()
{
	int n;
	cin >> n;
	int ans = 0;
	priority_queue<int> q;
	map<int, int> cnt;
	if (n >= 2)
	{
		q.push(n);
		cnt[n] ++ ;
	}
	while (q.size())
	{
		auto t = q.top();
		q.pop();
		ans += t * cnt[t];
		if (t % 2 == 0 && t / 2 >= 2)
		{
			if (cnt[t / 2] == 0) q.push(t / 2);
			cnt[t / 2] += 2 * cnt[t];
		}
		else if (t % 2 != 0 && t / 2 >= 2)
		{
			if (cnt[t / 2] == 0) q.push(t / 2);
			if (cnt[t / 2 + 1] == 0) q.push(t / 2 + 1);
			cnt[t / 2] += cnt[t];
			cnt[t / 2 + 1] += cnt[t];
		}
		else if (t % 2 != 0 && t / 2 + 1 >= 2)
		{
			if (cnt[t / 2 + 1] == 0) q.push(t / 2 + 1);
			cnt[t / 2 + 1] += cnt[t];
		}
	}
	cout << ans << '\n';
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	// cin >> t;
	while (t -- )
	{
		solve();
	}
}

ATC abc340D Super Takahashi Bros.

题目链接

第一次自己能很快想出d的思路,来源于一场牛客,也是类似的状态转移,但没有办法用dp做的问题,以后遇到这样的问题直接跑dijkstra吧,bfs可能会t

#include 

using namespace std;

#define int long long
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;

const int N = 2e5 + 10;
const int mod = 1e9 + 7;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int n;
	cin >> n;
	vector<int> a(n), b(n), x(n);
	for (int i = 1; i <= n - 1; i ++ ) cin >> a[i] >> b[i] >> x[i];
	priority_queue<PII, vector<PII>, greater<PII>> q;
	q.push({0, 1});
	vector<int> ans(n + 1, INF);
	ans[1] = 0;
	while (q.size())
	{
		auto t = q.top();
		q.pop();
		int ver = t.second, value = t.first;
		if (ans[ver + 1] > value + a[ver])
		{
			ans[ver + 1] = value + a[ver];
			if (ver + 1 != n) q.push({ans[ver + 1], ver + 1});
		}
		if (ans[x[ver]] > value + b[ver])
		{
			ans[x[ver]] = value + b[ver];
			if (x[ver] != n) q.push({ans[x[ver]], x[ver]});
		}
	}
	cout << ans[n] << '\n';
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	// cin >> t;
	while (t -- )
	{
		solve();
	}
}

ATC abc340E Mancala 2

题目链接

好激动!第一次没看题解自己写出来e(开心 ovo

看完题目脑子里就是区间修改+单点求和,所以直接用树状数组就可以啦,线段树也没问题,因为树状数组用的不太熟所以这一题用树状数组来写的

#include 

using namespace std;

#define int long long
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;

const int N = 2e5 + 10;
const int mod = 1e9 + 7;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

int tr[N];

inline int lowbit(int x)
{
	return x & -x;
}

void add(int pos, int x)
{
	for (int i = pos; i < N; i += lowbit(i)) tr[i] += x;
}

int query(int pos)
{
	int res = 0;
	for (int i = pos; i >= 1; i -= lowbit(i)) res += tr[i];
	return res;
}

void solve()
{
	int n, m;
	cin >> n >> m;
	vector<int> a(n + 1);
	for (int i = 1; i <= n; i ++ ) cin >> a[i];
	for (int i = 1; i <= n; i ++ ) add(i, a[i] - a[i - 1]); 
	vector<int> b(m + 1);
	for (int i = 1; i <= m; i ++ ) cin >> b[i], b[i] += 2;
	for (int i = 1; i <= m; i ++ )
	{
		int cnt = query(b[i] - 1);
		add(b[i] - 1, -cnt);
		add(b[i], cnt);
		add(b[i], 1);
		if (b[i] + cnt - 1 <= n) add(b[i] + cnt, -1);
		else
		{
			add(1, cnt / n);
			add(n + 1, -(cnt / n));
			cnt %= n;
			add(1, 1);
			add(1 + cnt, -1);
		}
	}
	for (int i = 1; i <= n; i ++ ) cout << query(i) << ' ';
	cout << '\n';
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	// cin >> t;
	while (t -- )
	{
		solve();
	}
}

ATC abc340F S = 1

题目链接

已知面积和底边,我们可以求出高h,现在我们的目的就是求距离已知的直线距离为h的直线有无解,扩欧就可以解决

#include 

using namespace std;

#define int long long
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;

const int N = 2e5 + 10;
const int mod = 1e9 + 7;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

int exgcd(int a, int b, int &x, int &y) // 扩展欧几里得
{
    if (b == 0)
    {
        x = 1;
        y = 0;
        return a;
    }
    int r = exgcd(b, a % b, x, y);
    int temp = y;
    y = x - (a / b) * y;
    x = temp;
    return r; // 得到a b的最大公因数
}

void solve()
{
	int a, b;
	cin >> a >> b;
	int x, y;
	int tmp = exgcd(-b, a, x, y);
	if (2 % tmp != 0) cout << -1 << '\n';
	else
	{
		if (x == 0 && a == 0) swap(x, y);
		if (y == 0 && b == 0) swap(x, y);
		cout << x * 2 / tmp << ' ' << y * 2 / tmp << '\n';
		return;
	}
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	// cin >> t;
	while (t -- )
	{
		solve();
	}
}

ATC abc338F Negative Traveling Salesman

题目链接

还是没有养成注意数据范围的习惯,看见点数很少的时候应该直接往floyd上面想

然后考虑到需要判断每个点是否经过,于是往状压dp上想,一位代表一个点,这一位为1就说明已经经过该点

#include 

using namespace std;

#define int long long
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;

const int N = 2e5 + 10;
const int mod = 1e9 + 7;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int n, m;
	cin >> n >> m;
	vector<vector<int>> d(n + 1, vector<int>(n + 1, INF));
	for (int i = 1; i <= n; i ++ ) d[i][i] = 0;
	for (int i = 1; i <= m; i ++ )
	{
		int u, v, w;
		cin >> u >> v >> w;
		d[u][v] = w;
	}
	for (int k = 1; k <= n; k ++ )
		for (int i = 1; i <= n; i ++ )
			for (int j = 1; j <= n; j ++ )
				d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
	vector<vector<int>> dp((1 << n), vector<int>(n + 1, INF));
	for (int i = 1; i <= n; i ++ ) dp[(1 << (i - 1))][i] = 0;
	for (int bit = 1; bit < (1 << n); bit ++ )
	{
		for (int i = 1; i <= n; i ++ )
		{
			if ((bit >> (i - 1)) & 1 == 0) continue;
			if (dp[bit][i] == INF) continue;
			for (int j = 1; j <= n; j ++ )
			{
				if (((bit >> (j - 1)) & 1) == 1) continue;
				if (d[i][j] == INF) continue;
				dp[bit | (1 << (j - 1))][j] = min(dp[bit | (1 << (j - 1))][j], dp[bit][i] + d[i][j]);
			}
		}
	}
	int ans = INF;
	for (int i = 1; i <= n; i ++ ) ans = min(ans, dp[(1 << n) - 1][i]);
	if (ans == INF) cout << "No" << '\n';
	else cout << ans << '\n';
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	// cin >> t;
	while (t -- )
	{
		solve();
	}
}

ATC abc337C Lining Up 2

题目链接

水题

#include 

using namespace std;

#define int long long
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;

const int N = 2e5 + 10;
const int mod = 1e9 + 7;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int n;
	cin >> n;
	vector<int> a(n + 1);
	int flag;
	for (int i = 1; i <= n; i ++ )
	{
		int x; cin >> x;
		if (x == -1) flag = i;
		else a[x] = i;
	}
	cout << flag << ' ';
	int idx = flag;
	while (a[idx])
	{
		cout << a[idx] << ' ';
		idx = a[idx];
	}
	cout << '\n';
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	// cin >> t;
	while (t -- )
	{
		solve();
	}
}

ATC abc337D Cheating Gomoku Narabe

题目链接

真是煞笔了花了一个多小时写一道前缀和,一开始给x的地方定义成无穷大,后来才发现如果一排全都是x,无穷大不断累加是会爆longlong的,之后要注意这一点

#include 

using namespace std;

#define int long long
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;

const int N = 2e5 + 10;
const int mod = 1e9 + 7;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int n, m, k, ans = INF;
	cin >> n >> m >> k;
	vector<vector<int>> g(n + 1, vector<int>(m + 1));
	vector<vector<int>> x(n + 1, vector<int>(m + 1));
	for (int i = 1; i <= n; i ++ )
		for (int j = 1; j <= m; j ++ )
		{
			char c; cin >> c;
			if (c == 'x') x[i][j] = 1;
			else if (c == '.') g[i][j] = 1;
		}

	vector<vector<int>> pre1(n + 1, vector<int>(m + 1));
	vector<vector<int>> x1(n + 1, vector<int>(m + 1));
	for (int i = 1; i <= n; i ++ )
		for (int j = 1; j <= m; j ++ )
		{
			x1[i][j] = x1[i][j - 1] + x[i][j];
			pre1[i][j] = pre1[i][j - 1] + g[i][j];
		}
	for (int i = 1; i <= n; i ++ )
		for (int j = k; j <= m; j ++ )
			if (x1[i][j] - x1[i][j - k] != 0) continue;
			else ans = min(ans, pre1[i][j] - pre1[i][j - k]);
	vector<vector<int>> pre2(n + 1, vector<int>(m + 1));
	vector<vector<int>> x2(n + 1, vector<int>(m + 1));
	for (int j = 1; j <= m; j ++ )
		for (int i = 1; i <= n; i ++ )
		{
			x2[i][j] = x2[i - 1][j] + x[i][j];
			pre2[i][j] = pre2[i - 1][j] + g[i][j];
		}
	for (int j = 1; j <= m; j ++ )
		for (int i = k; i <= n; i ++ )
			if (x2[i][j] - x2[i - k][j] != 0) continue;
			else ans = min(ans, pre2[i][j] - pre2[i - k][j]);

	if (ans == INF) cout << -1 << '\n';
	else cout << ans << '\n';
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	// cin >> t;
	while (t -- )
	{
		solve();
	}
}

你可能感兴趣的:(2024寒假训练记录,算法)