Educational Codeforces Round 136 (Rated for Div. 2)

题目链接

A

核心思路:其实就是一个签到题没什么好说的,我们可以直接通过观察样例大胆猜测结论:也就是只有是一列的时候是完全孤立的。直接看代码吧.

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define IOS std::ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
const int INF = 1e8;
const int N = 1e6 + 10, S = 55, M = 10000010;
int n, root, idx;
void solve()
{
	int n, m;
	cin >> n >> m;
	if (n == 1 || m == 1)
		cout << "1" << " " << "1" << endl;
	else
		cout << "2" << " " << "2" << endl;
}
int main()
{
	int T;
	cin >> T;
	while (T--)
	{
		solve();
	}
}

B

核心思路:其实就是我们对数学公式化简就好了。题目是要我们\(a[i]=abs(d[i]-d[i-1])\),又因为我们的a[i]都是正数,所以就可以推导出\(a[i-1]\geq d[i]\)并且d[i]需要大于0(这个是题目要求的).

由于是我们可以有一边构造,一边看是否满足条件就好了。构造的话可以采用a[i]=a[i-1]+d[i],因为这种构造可以使得a[i]尽可能地大.

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define IOS std::ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
const int INF = 1e8;
const int N = 1e6 + 10, S = 55, M = 10000010;
int n, root, idx;
int a[N], d[N];
void solve()
{
	int n;
	cin >> n;
	for (int i = 1;i <= n;i++)
		cin >> d[i];
	a[1] = d[1];
	for (int i = 1;i <= n;i++)
	{
		if (d[i] > 0 && a[i - 1] >= d[i])
		{
			cout << -1 << endl;
			return;
		}
		a[i] = a[i - 1] + d[i];
	} 
	for (int i = 1;i <= n;i++)
	{
		cout << a[i] << " ";
	}
	cout << endl;
}
int main()
{
	int T;
	cin >> T;
	while (T--)
	{
		solve();
	}
}

C

核心思路:像这种博弈论的题目,其实我们可以联想dp。因为博弈论也一定是可以把每一个局面使用状态表示出来,所以我们可以先推导两组数据,然后推导到一般情况,也就是求出来一个递推式.

首先我们可以发现最小的一个局面时n=4,因为这个刚好使A和B都执行了一轮情况。也是我们可以先推导n=8这种情况。然后再推导到一般的情况来求递推式子.

其实我们可以通过样例1发现平局就那么一种情况

A必胜:

  1. 拿到了8这种牌,也就是\(C_{7}^{3}\).
  2. 拿到了567,我们就可以使用5逼出对手的8.然后就又是必胜的局面。方案数:\(C_{4}^{1}\),因为8在对手那里.
  3. 拿到了67,我们可以发现这种就是平局。于是我们来到了局面4这种情况.

所以公式就是:\(f[i]=C[i-1][i/2]+C[i-4][i/2-3]+f[i-4]\).

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define IOS std::ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
const int INF = 1e8;
const int N = 100;
LL C[N][N];
LL f[N];
LL mod = 998244353;
void init()
{
	for (int i = 0; i < 100; i++)
		for (int j = 0; j < 100; j++)
			if (!j) C[i][j] = 1;
			else C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;

	f[2] = 1;
	f[4] = 3;
	for (int i = 6; i <= 60; i += 2) {
		f[i] = (C[i - 1][i / 2] + C[i - 4][i / 2 - 3] + f[i - 4]) % mod;
	}
}

void solve()
{
	int n;
	cin >> n;
	int sum = C[n][n / 2];
	int a = f[n];
	int b = ((sum - a - 1) % mod + mod) % mod;
	int c = 1;
	cout << a << " " << b << " " << c << endl;
}
int main()
{
	init();
	int T;
	cin >> T;
	while (T--)
	{
		solve();
	}
}

D

核心思路这里我们可以从底部往上面去统计深度以及推导过程,还有个注意的地方是看清楚题目问的是什么:他是要我们求最大深度最小,所以我们肯定需要使用二分去确定答案。

接下来就是怎么去搜索这一颗树:我们假设mid是我们要的深度,那么是不是从底往上统计深度的时候超过mid的,我们就需要进行操作。将这颗子树接到我们的根节点,接到根节点之后就把这颗子树的深度设为0,也就是重新操作下.

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define IOS std::ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
const int N = 2e5 + 10, M = 2 * N, INF = 1e9;
int n, m, k;
int h[N], e[M], ne[M], idx, fa[M];
int cnt;
void add(int a, int b)
{
	e[idx] = b;
	ne[idx] = h[a];
	h[a] = idx++;
}
int dfs(int u, int father, int mid)
{
	int maxv = 0;//每次都把我们的最大深度先置为0
	for (int i = h[u];~i;i = ne[i])
	{
		int j = e[i];
		if (j == father)
			continue;//说明就是叶子节点 
		maxv = max(maxv, dfs(j, u, mid));
	}
	maxv++;//深度加加
	if (father == 1 || u == 1)//如果是根节点那就不可以修改
		return 0;
	if (maxv >= mid)
	{
		cnt++;
		return 0;
	}
	else return maxv;
}
int check(int mid)
{
	cnt = 0;
	dfs(1, 0, mid);//这里把1的父亲置为0是为了防止被误判为根节点
	return cnt <= k;
}
void solve()
{
	cin >> n >> k;
	memset(h, -1, sizeof h);
	idx = 0;
	for (int i = 2;i <= n;i++)
	{
		int y;
		cin >> y;
		add(i, y);
		add(y, i);
	}
	int l = 1;
	int r = n;
	while (l < r)
	{
		int mid = l + r >> 1;
		if (check(mid))
			r = mid;
		else
			l = mid + 1;
	}
	cout << r << endl;
}
int main()
{
	int T;
	cin >> T;
	while (T--)
	{
		solve();
	}
}
posted @ 2022-12-15 17:42  努力的德华  阅读(32)  评论(0)    收藏  举报