Codeforces训练(1900-2100)

本文介绍了三道代码竞赛题目,包括数组删除元素以实现整除、矩阵异或变换以及图的最短路径问题。通过动态规划、并查集和BFS等算法,分别对题目进行了详细解答,并提供了AC代码。这些题目考察了选手的数据结构和算法应用能力。
摘要由CSDN通过智能技术生成

前言

最近codeforce打的不是很好,所以专门进行一次训练,下面题目的难度全在 1900 − 2100 1900-2100 19002100难度区间。

CF1475G Strange Beauty

题目链接:CF1475G Strange Beauty
题目大意:给定一个数组,求最少删去多少个数,使得剩下的所有元素互相整除。
数据范围: 1 ≤ t ≤ 10 , 1 ≤ n ≤ 2 ∗ 1 0 5 , 1 ≤ a [ i ] ≤ 2 ∗ 1 0 5 1\le t\le 10,1\le n\le2*10^5,1\le a[i]\le 2*10^5 1t10,1n2105,1a[i]2105
题解:采取 d p dp dp方法, d p [ i ] dp[i] dp[i]表示以 i i i为最小元素的情况下,能最大包含多少元素。转移就是 d p [ i ] = ( m a x i ∣ j d p [ j ] ) + n u m [ i ] dp[i]=(\mathop{max}\limits_{i|j} dp[j])+num[i] dp[i]=(ijmaxdp[j])+num[i]
时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
AC代码:

#include<bits/stdc++.h>

#define ld long double
#define ll long long
using namespace std;
template<class T>
void read(T& x)
{
	T res = 0, f = 1; char c = getchar();
	while (!isdigit(c)) {
		if (c == '-')f = -1; c = getchar();
	}
	while (isdigit(c)) {
		res = (res << 3) + (res << 1) + c - '0'; c = getchar();
	}
	x = res * f;
}
const ll N = 200000 + 10;
const int mod = 1e9 + 7;
int t, a[N],n,num[N],dp[N];
int mx = 200000;

int main()
{
	//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
	freopen("test.in", "r", stdin);
#endif // ONLINE_JUDGE
	read(t);
	while (t--)
	{
		for (int i = 1; i <= mx; i++)num[i] = 0,dp[i]=0;
		read(n); 
		for (int i = 1; i <= n; i++)
		{
			read(a[i]); num[a[i]]++;
		}
		int ans = 0;
		for (int i = mx; i >=1; i--)
		{
			if (num[i] == 0)continue;
			dp[i] = num[i];
			for (int j = 2; j * i <= mx; j++)
			{
				dp[i] = max(dp[i], dp[i * j] + num[i]);
			}
			ans = max(ans, dp[i]);
		}
		printf("%d\n", n - ans);
		
	}

	return 0;
}

CF1475F Unusual Matrix

题目链接:CF1475F Unusual Matrix
题目大意:给定两个 n ∗ n n*n nn大小的 01 01 01数组 a , b a,b a,b。每次操作可以选择 a a a的一行或者一列对 1 1 1进行异或,问是否有可能让 a = b a=b a=b
数据范围: 1 ≤ n ≤ 1000 1\le n \le 1000 1n1000
题解:采用并查集来求解,我们知道一行 o r or or一列最多翻转一次。如果 a [ i ] [ j ] = = b [ i ] [ j ] a[i][j]==b[i][j] a[i][j]==b[i][j]意味着第 i i i行和第 j j j列翻转的次数是相同的,否则两者翻转的次数是不同的。这种关系我们可以使用并查集来维护,只要发现了有矛盾就意味着不成立。如果要求输出操作序列,可以使用 2 − s a t 2-sat 2sat来求解。
AC代码:

#include<bits/stdc++.h>

#define ld long double
#define ll long long
using namespace std;
template<class T>
void read(T& x)
{
	T res = 0, f = 1; char c = getchar();
	while (!isdigit(c)) {
		if (c == '-')f = -1; c = getchar();
	}
	while (isdigit(c)) {
		res = (res << 3) + (res << 1) + c - '0'; c = getchar();
	}
	x = res * f;
}
const ll N = 2000 + 10;
const int mod = 1e9 + 7;
int f[N * 10];
int t, n, a[N][N], b[N][N];
int find(int x)
{
	return x == f[x] ? f[x] : f[x] = find(f[x]);
}
#define r(x) (x+n)
#define c(x) (x)
#define fm(x) (x+2*n)
int main()
{
	//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
	freopen("test.in", "r", stdin);
#endif // ONLINE_JUDGE
	read(t);
	while (t--)
	{
		read(n);
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= n; j++)
				scanf("%1d", &a[i][j]);
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= n; j++)
				scanf("%1d", &b[i][j]);
		for (int i = 1; i <= n; i++)
		{
			f[r(i)] = r(i);
			f[fm(r(i))] = fm(r(i));
			f[c(i)] = c(i);
			f[fm(c(i))] = fm(c(i));
		}
		bool isok = 1;
		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= n; j++)
			{
				if (a[i][j] == b[i][j])
				{
					if (find(r(i)) == find(fm(c(j))) || find(c(j)) == find(fm(r(i))))isok = 0;
					f[find(r(i))] = find(c(j));
					f[find(fm(r(i)))] = find(fm(c(j)));
				}
				else
				{
					if (find(r(i)) == find((c(j))) || find(fm(c(j))) == find(fm(r(i))))isok = 0;
					f[find(r(i))] = find(fm(c(j)));
					f[find(fm(r(i)))] = find(c(j));
				}
			}
		}
		printf("%s\n", isok ? "YES" : "NO");
	}

	return 0;
}

CF1472G Moving to the Capital

题目链接:CF1472G Moving to the Capital
题目大意:emmm,好长好长,自己看翻译。
题解:很显然要先求出 d d d数组,然后我们处理最大使用一次的反边,其实就是不管 d [ i ] d[i] d[i] d [ t o ] d[to] d[to]的大小,我们直接进行转移。最后我们来处理每一个点可以到达的最优点。 a n s [ i ] = m i n j ∈ i 能 达 到 的 集 合 a n s [ j ] ans[i]=\mathop{min}\limits_{j\in{i能达到的集合}}ans[j] ans[i]=jiminans[j]
AC代码:

#include<bits/stdc++.h>

#define ld long double
#define ll long long
using namespace std;
template<class T>
void read(T& x)
{
	T res = 0, f = 1; char c = getchar();
	while (!isdigit(c)) {
		if (c == '-')f = -1; c = getchar();
	}
	while (isdigit(c)) {
		res = (res << 3) + (res << 1) + c - '0'; c = getchar();
	}
	x = res * f;
}
const ll N = 200000 + 10;
const int mod = 1e9 + 7;
int t, n, m,d[N],ans[N];
vector<int>p[N];
bool vis[N];
void bfs(int u)
{
	queue<int>pls;
	pls.push(u);
	
	d[u] = 0; vis[u] = 1;
	while (pls.size())
	{
		int f = pls.front(); pls.pop(); vis[f] = 0;
		for (auto to : p[f])
		{
			if (d[to] > d[f] + 1)
			{
				d[to] = d[f] + 1;
				if (!vis[to])
				{
					pls.push(to);
					vis[to] = 1;
				}
			}
		}

	}
}
void dfs(int u)
{
	vis[u] = 1;
	for (auto to : p[u])
	{
		if (d[to] <=d[u])continue;
		if(!vis[to])dfs(to);
		ans[u] = min(ans[u], ans[to]);
	}
}
int main()
{
	//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
	freopen("test.in", "r", stdin);
#endif // ONLINE_JUDGE
	read(t);
	while (t--)
	{
		read(n); read(m);
		for (int i = 1; i <= n; i++)p[i].clear();
		for (int i = 1; i <= n; i++)d[i] = 0x3f3f3f3f,ans[i]=d[i],vis[i]=0;
		for (int i = 1; i <= m; i++)
		{
			int x, y; read(x), read(y); p[x].push_back(y);
		}
		bfs(1);
		for (int i = 1; i <= n; i++)
		{
			ans[i] = d[i];
			for (auto to : p[i])
			{
				ans[i] = min(ans[i], d[to]);
			}
		}
		dfs(1);
		for (int i = 1; i <= n; i++)printf("%d ", ans[i]);
		printf("\n");
	}
	return 0;
}

### 回答1: 我可以分享一种有效的训练计划,以达到codeforces橙名。首先,建立一个长期的训练计划,每周至少完成3-4个题目,把每个题目的解题过程都认真的思考一遍,确保理解每一步的思路。建议每隔一段时间,做一次综合练习,以更好地检验自己的知识水平。此外,参加竞赛也可以加深对算法的理解,从而提升解题能力。 ### 回答2: 想要在Codeforces达到橙名的水平,需要进行系统性的训练,并掌握一定的算法和编程技巧。以下是一个可能的训练计划: 1. 学习基础知识:首先,建议你系统地学习计算机科学的基础知识,包括数据结构和算法。这可以帮助你理解不同问题的解决方案,并优化代码的执行效率。 2. 解决题目:开始刷题是锻炼算法和编码能力的关键。选择一些简单的题目,如Codeforces的Div2 A、B级题目,按难度逐渐增加。通过不断解决题目,你将熟悉各种算法,并提高编写清晰、高效代码的能力。 3. 学习算法:学习和掌握一些常用算法,如贪心、动态规划、图论等。理解算法原理,分析其时间和空间复杂度,并通过练习将其应用于具体的问题。 4. 参加比赛:参加Codeforces的比赛是衡量自己水平的好方法。开始参加Div2级别的比赛,并争取在中等难度的题目上取得好成绩。逐渐挑战3级、4级比赛,尽量与更强的选手竞争,以提高自己的水平。 5. 反思和学习:每次比赛后,对自己的解题过程进行反思和总结。分析解错的原因,学习其他参赛选手的思考方式和技巧。通过学习他人的优秀代码和解题思路,不断提升自己的编码能力。 6. 练习编码技巧:除了算法,熟练掌握编码技巧也非常重要。学习并应用一些常用的数据结构和STL库,如数组、链表、栈、队列等。多写一些小项目或练习题,锻炼自己的编码能力。 7. 时间管理:合理安排学习和练习的时间。每天保持一定时间的刷题和学习,坚持养成好的学习习惯。同时,在比赛中也要控制好时间,并尽量在限定时间内完成题目。 总之,达到Codeforces橙名的水平需要长期的训练和不断的学习。通过刷题、学习算法和编码技巧、参加比赛以及反思总结,你可以逐渐提升自己的水平,并取得理想的成绩。记住,坚持和持续学习是达到目标的关键。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值