Codeforces Round #829 (Div. 2)

1|0A

核心思路:我们会发现如果就这么从左向右处理好像不太好处理的样子。因为最后几个Q我们不好去计算了,所以这里有一个很巧妙的点,那就是把那个字符串给逆序,然后我们从左往右统计A和Q,遇到A就是++,Q就--.如果小于0就一定不是了。

#include<bits/stdc++.h> #include<unordered_map> using namespace std; typedef long long ll; const int N = 1e5+10;//表示的是高精度位数 char s[N]; int vis[N]; int main() { int t; cin >> t; while (t--) { int n; cin >> n; string s; cin >> s; reverse(s.begin(), s.end()); int a = 0; int flag = 0; for (auto x : s) { if (x == 'A') a++; if (x == 'Q') a--; if (a < 0) { cout << "No" << endl; flag = 1; break; } } if(!flag) cout << "Yes" << endl; } }

2|0B

核心思路:这个题目其实想思路并不困难,观察下规律就出来了,写代码稍微困难点。刚开始想偏了,以为需要双指针,其实就是一个规律题。这个选取跨度长度比较关键,选择n/2最好,这样1最后一个数就方便一点,如果是n则需要再进行处理

#include<bits/stdc++.h> #include<unordered_map> using namespace std; typedef long long ll; const int N = 1e5+10;//表示的是高精度位数 char s[N]; int vis[N]; void solve() { int n; cin >> n; int t = n / 2; for (int i = 1;i <= t;i++) { cout << i + t << " "; cout << i << " "; } if (n % 2 == 1) cout << n << endl; else cout << endl; } int main() { int t; cin >> t; while (t--) { solve(); } }

3|0C1

核心思路:这里我们先统计处前缀和sum,然后我要注意一个点,那就是ai要么是-1,要么是1.然后我们想怎么可以通过合并来改变sum的值。我们就从最基本的合并两个数来分析,这两个数最多只有四种组合情况。比如-1,1.原来的sum=0,合并后是不是等于-2,所以会造成sun-=2;接下来几种情况依然是这么分析,所以我们可以进行以下分类:

  1. sum>0
  • ai=1,ai+1=1

  • ai=1,ai+1=1

  1. sum<0
  • ai=1,ai+1=1

  • ai=1,ai+1=1

这样分类就会不重不漏了,然后我们可以设立一个数组记录我们更新完之后的下标,其实情况就选一个数就好了,因为题目是允许的。这个数组的更新是值得学习的

#include<bits/stdc++.h> #include<unordered_map> using namespace std; typedef long long ll; const int N = 1e7 + 10;//表示的是高精度位数 int n, a[N], ne[N]; void solve() { int n; cin >> n; int sum = 0; int res = n; for (int i = 1;i <= n;i++) cin >> a[i]; for (int i = 1;i <= n;i++) { sum += a[i]; ne[i] = i; } if (abs(sum) & 1) { cout << -1 << endl; return; } for (int i = 1; i < n; i++) { if (sum < 0) { if (a[i] == 1 && a[i + 1] == -1) { ne[i] = i + 2; i++; sum += 2; res--; } else if (a[i] == -1 && a[i + 1] == -1) { ne[i] = i + 2; sum += 2; i++; res--; } } else if (sum > 0) { if (a[i] == -1 && a[i + 1] == 1) { ne[i] = i + 2; sum -= 2; i++; res--; } else if (a[i] == 1 && a[i + 1] == 1) { ne[i] = i + 2; sum -= 2; i++; res--; } } if (sum == 0) break; } cout << res << '\n'; for (int i = 1; i <= n; i++) { if (ne[i] == i) cout << i << " " << i << '\n'; else { cout << i << " " << ne[i] - 1 << '\n'; i = ne[i] - 1; } } } int main() { int t; cin >> t; while (t--) { solve(); } }

4|0C2

核心思路:这一题是和上一题差不多的。大同小异,就是需要多讨论一种情况.

#include<bits/stdc++.h> #include<unordered_map> using namespace std; typedef long long ll; const int N = 1e7 + 10;//表示的是高精度位数 int n, a[N], ne[N]; void solve() { int n; cin >> n; int sum = 0; int res = n; for (int i = 1;i <= n;i++) cin >> a[i]; for (int i = 1;i <= n;i++) { sum += a[i]; ne[i] = i; } if (abs(sum) & 1)//因为只会将sum+=2或者-=2 { cout << -1 << endl; return; } for (int i = 1; i < n; i++) { if (sum < 0) { if (a[i] == 1 && a[i + 1] == -1) { ne[i] = i + 2; i++; sum += 2; res--; } else if (a[i] == -1 && a[i + 1] == -1) { ne[i] = i + 2; sum += 2; i++; res--; } else if (a[i] == 0 && a[i + 1] == -1)//为什么这么省掉了(-1,0)这种情况呢,我们使用反证法会发现压根不会改变sum的值所以不需要讨论 { ne[i] = i + 2; sum += 2; i++; res--; } } else if (sum > 0) { if (a[i] == -1 && a[i + 1] == 1) { ne[i] = i + 2; sum -= 2; i++; res--; } else if (a[i] == 1 && a[i + 1] == 1) { ne[i] = i + 2; sum -= 2; i++; res--; } else if (a[i] == 0 && a[i + 1] == 1) { ne[i] = i + 2; sum -= 2; i++; res--; } else if (a[i] == 0 && a[i + 1] == 1) { ne[i] = i + 2; sum -= 2; i++; res--; } } if (sum == 0) break; } cout << res << '\n'; for (int i = 1; i <= n; i++) { if (ne[i] == i) cout << i << " " << i << '\n'; else { cout << i << " " << ne[i] - 1 << '\n'; i = ne[i] - 1; } } } int main() { int t; cin >> t; while (t--) { solve(); } }

5|0D

核心思路:其实我们需要先观察阶乘分解的规律:例如:4!=1!+1!+2!+2!+3!+3!+3!,所以我们

从前往后枚举1-n中的所有数,如果都满足数x的阶乘出现的次数可以被x+1整除,那么就说明是成立的。

#include<bits/stdc++.h> #include<unordered_map> using namespace std; typedef long long ll; const int N = 1e7 + 10;//表示的是高精度位数 int cnt[N]; int a[N]; void solve() { int n, x; cin >> n >> x; for (int i = 1;i <= n;i++) cin >> a[i]; for (int i = 1;i <= n;i++) cnt[a[i]]++; for (int i = 1;i < x;i++) { if (cnt[i] % (i + 1)) { cout << "No" << endl; return; } cnt[i + 1] += cnt[i] / (i + 1); } cout << "Yes" << endl; } int main() { solve(); }

6|0E

核心思路:这是个dp问题

  1. 集合定义:dp[i]表示还有i个位置需要进行交换。i是指我们没有排号的点数。

  2. 集合划分:我们我们把这个集合划分为两个状态,一种是我们选到了第i个点,首先分析我们选到了第i个点的概率:ii/(Cn2),然后我们分析为什么分子是i*i,因为我们那个点的数字要么是1,要么是0,我们还需要直到如果有i个i没有排好,那么肯定就对应i个0也没有排好,所以总数是ii.然后没有选到的点的数目就一定是:1(ii)/(Cn2).

  3. 状态转移方程:dp[i]=dp[i1](ii)/(Cn2)+dp[i](1(ii)/Cn2)+1,化简可以得:dp[i]=dp[i-1]+Cn2/(ii)

接下来就需要统计下有多少个需要交换的数字就好了,这个也很简单,直接看代码就好了。

#include<bits/stdc++.h> #include<unordered_map> using namespace std; typedef long long ll; const int N = 1e7 + 10;//表示的是高精度位数 int mod = 998244353; int a[N]; int qmi(int a, int b) { int res = 1; while (b) { if (b & 1) res = res * a % mod; b >>= 1; a = a * a % mod; } return res; } void solve() { int n; cin >> n; int res = 0; int ans = 0; int cnt = 0; for (int i = 1;i <= n;i++) { cin >> a[i]; cnt += (a[i] == 0); } for (int i = 1;i <= cnt;i++) { if (a[i] != 0) res++; } for (int i = 1;i <= res;i++) { ans = (ans + (n * (n - 1) / 2)%mod * qmi(i * i%mod, mod - 2) % mod) % mod;//这里用到了费马小定理应为i*i是肯定和mod互为质数的 } cout << ans << endl; } int main() { int t; cin >> t; while (t--) { solve(); } }

链接


__EOF__

本文作者肖英豪
本文链接https://www.cnblogs.com/xyh-hnust666/p/16925173.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   努力的德华  阅读(23)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示