Codeforces Round #564 (Div. 2) A-D

A. Nauuo and Votes

题意:
  给我们x张赞成票和y张否决票还有z张不确定的票,让我们判断最后的选举结果是什么,如果是赞成的是"+", 否决的是"-", 不确定的是"?", 平票的是"0"
思路:
  分类讨论一下就行了

int x, y, z; std::cin >> x >> y >> z; if (x > y + z) std::cout << "+\n"; else if (x + z < y) std::cout << "-\n"; else if (x == y && !z) std::cout << "0\n"; else if (x + z >= y || y + z <= x) std::cout << "?\n";

B. Nauuo and Chess

题意:
  给我们n个数,这n个数的范围是1xn,且这n个数互不相同。要求我们构造一个mm的网格,将这n个数放进去,且满足|rirj|+|cicj||ij|。第一行输出m,接下来的m行输出n个点的坐标。
思路:
  要让这个网格尽可能的小,也就是要让这个网格满足m1+m1n1。那么根据这个表达式我们可以推出在满足刚好把n个数放下的最小的m值。
m=n(n%2!=0)2+1。接下来我们就只需要思考怎么构造了。我们先把1放在网格的左上角即(1,1), n放在(m,m),然后我们就只需要在第一行和最后一行放数就可以了。我们知道(1,1)(m,m)之间的曼哈顿距离为m1+m1,且m1+m1n1 所以我们把n1放在(m,m1)的位置一定也满足这个条件。

void solve() { int n; std::cin >> n; int m = (n - n % 2) / 2 + 1; std::cout << m << "\n"; std::vector<std::pair<int, int>> v(n + 1); int idx = 0; for (int i = n; i > n - m; i --, idx ++ ) v[i] = {m, m - idx}; for (int i = 1; i <= n - m; i ++ ) v[i] = {1, i}; for (int i = 1; i <= n; i ++ ) std::cout << v[i].first << " " << v[i].second << "\n"; }

C. Nauuo and Cards

题意:
  有两堆牌每一堆牌都有n张且有n张是0,另外n张是1n的排列,自己手中的牌可以按照自己的意愿打出,并放入另外一堆的牌底。每一次都可以从牌堆顶获得一张牌。要我们求出使得牌堆内的元素从牌堆顶到牌堆底是单调递增的操作次数。
思路:
  因为我们要让不在手中的牌是n张牌1n的单调递增的排列方式,所以我们首先要找到1的位置。如果1是在自己的手中的话,我们就要求出使得我们在牌堆底不断加数得时候能够让第x张能够被获得且打出,所以最后得答案就是max0in1{ibi+2}+n。如果1是在牌堆中,并且在1后面得数是公差为1得等差数列,并且前面的非0数可以在轮到它插入牌堆底之前或那一刻出队,答案就是pos1。否则的话答案就是max0in1{ibi+2}+n

void solve() { int n; std::cin >> n; std::vector<int> a(n), b(n); int pos = -1; for (auto& I : a) std::cin >> I; rep(i, 0, n) { std::cin >> b[i]; if (b[i] == 1) pos = i; } if (~pos) { bool f = true; rep(i, pos + 1, n) if (b[i] != b[i - 1] + 1) { f = false; break; } // 判断1后面的数是不是连续的 rep(i, 0, pos) if (b[i] && b[i] - i - 1 <= n - pos) { f = false; break; } // b[i] - i - 1表示的是这个数到出队的时候能不能接在当时的后面 if (f) {std::cout << pos << "\n"; return ;} // 如果全部都满足的话就只需要操作pos次 } int ans = 0; rep(i, 0, n) if (b[i]) ans = std::max(ans, i - b[i] + 2); std::cout << ans + n << "\n"; // 如果上面的要求都不满足的话队列一定要全部清空一遍所以+n }

D. Nauuo and Circle

题意:
  给定一棵n个节点的树,从1n编号,现在你需要玩弄这棵树。问按照顺时针遍历能获得多少种不同的序列。最后的答案对%998244353
思路:
  定义son[u]表示u的子节点的个数。先固定1是这个序列中的第一个,因为这是一个环所以最后的答案要乘上n。定义dp[u]表示的是以u为节点的方案数。
  对于节点1,我们可以就是对son[u]进行全排列,并将排列方式放在1的后面,将son[u]全排列一共有Ason[u]son[u]种方案,也就是son[u]!种方案,而它的每一个儿子v同样也有它们的子节点,所以就得到了式子dp[u]=son[u]!vG[u]dp[v]
而对于非1节点,它们自身也可以进行全排列所以对于非1的节点,它们的方案数的表达式是dp[u]=(son[u]+1)!vG[u]dp[v]
所以最后我们将两种情况合并就是dp[u]=du[u]!vG[u]dp[v]其中du[u]表示的是du[u]的度

void solve() { int n; std::cin >> n; fac[0] = 1; rep(i,1,N) fac[i] = fac[i - 1] * i; std::vector<int> G[n + 1], du(n + 1); rep(i,0,n - 1) { int u, v; std::cin >> u >> v; G[u].push_back(v), G[v].push_back(u); du[v] ++, du[u] ++; } std::vector<Z> dp(n + 1); std::function<void(int, int)> dfs = [&] (int u, int fa) -> void { Z res = 1; for (auto v : G[u]) { if (v == fa) continue; dfs(v, u); res = res * dp[v]; } dp[u] = fac[du[u]] * res; }; dfs(1, 0); Z ans = dp[1] * n; std::cout << ans.val() << "\n"; }

__EOF__

本文作者HoneyGrey
本文链接https://www.cnblogs.com/Haven-/p/16151688.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   浅渊  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示