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必胜:
- 拿到了8这种牌,也就是\(C_{7}^{3}\).
- 拿到了567,我们就可以使用5逼出对手的8.然后就又是必胜的局面。方案数:\(C_{4}^{1}\),因为8在对手那里.
- 拿到了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();
}
}
标签:std,Educational,Rated,cout,int,Codeforces,long,mid,tie
From: https://www.cnblogs.com/xyh-hnust666/p/16985706.html