Codeforces Round 195 (Rated for Div. 2)
CF爆炸了没办法提交评测说是

A. Perfect Sandwiches #
Monocarp 有 \(a\) 片奶酪和 \(b\) 片香肠。他想用这些为他的朋友们制作尽可能多份的三明治。
Monocarp 非常节俭,因此他必须用光所有的 \(a\) 片奶酪和所有的 \(b\) 片香肠来制作三明治,不能有任何剩余。此外,他制作三明治有以下规定:
- 每份三明治必须至少包含一片奶酪和至少一片香肠;
- 每片奶酪和每片香肠都必须且只能放在一份三明治上;
- 对于每份三明治,奶酪的片数必须严格大于香肠的片数。
请帮助 Monocarp 确定他最多能制作多少份三明治,或者判断是否无法按照这些规定分配所有的切片。
输入
第一行包含一个整数 \(t\)(\(1 \le t \le 10^4\))—— 测试用例的数量。
每个测试用例的唯一一行包含两个整数 \(a\) 和 \(b\)(\(1 \le a, b \le 100\))—— 分别代表奶酪和香肠的片数。
输出
对于每个测试用例,输出一个整数 —— 能够制作的最大三明治数量。如果无法按照所述规定分配所有切片,则输出 -1。
容易得到有解的限制条件是 \(a>b\)
在有解的基础上,做 \(k\) 份三明治,最少需要 \(b+k\) 片奶酪。也就是 \(a\gt b+k\),由此解出 \(k\) 的最大值。
#include<bits/stdc++.h>
using namespace std;
int main(){
int t;
cin>>t;
while(t--){
int a,b;cin>>a>>b;
cout<<(a<=b?-1:min(b,a-b))<<endl;
}
}
B. Replace and Compress #
给你一个长度为 \(n\) 的字符串 \(s\),仅由字符 0 和/或 1 组成。你需要执行恰好一次操作,该操作包含两个步骤:
- 从索引 \(2\) 到 \(n-1\)(包含两端)中至多选择一个字符,并将其替换为相反的字符:
0变1或1变0。你可以选择不改变任何字符。字符串的第一个和最后一个字符不能被改变; - 将每一段连续的相同字符组成的极大块替换为一个该字符。
如果一段字符无法通过向左或向右添加相同字符来扩展,则称其为极大块。例如,在第二步之后,字符串 100111011 将变为 10101。
请计算执行此操作后可以得到的不同字符串的数量。
输入
第一行包含一个整数 \(t\)(\(1 \le t \le 10^4\))—— 测试用例的数量。
每个测试用例包含一行,包含一个仅由字符 0 和 1 组成的字符串 \(s\)(\(3 \le |s| \le 3 \cdot 10^5\))。
关于输入的附加限制:
- 所有测试用例中字符串 \(s\) 的长度之和不超过 \(3 \cdot 10^5\)。
输出
对于每个测试用例,输出一个整数 —— 执行操作后可以得到的不同字符串的数量。
注意到我们不能改变首位字符,并且最后的字符串内一定没有连续相同的字符。
这就意味着:最终,相同长度的字符串一定是同一个字符串。原问题也即求共可能会出现多少不同长度的字符串。
除了不做修改出现的字符串以外。还可能有
- 通过把一个单独的数字替换为与其左右相同的数字使长度减少 \(2\)。 只需判断是否存在单独数字即可。
- 通过把长度至少为 \(3\) 的连通块中间的数字反转使长度增加 \(2\)。 只需判断是否存在连通块长度大于等于 \(3\) 即可。
#include<bits/stdc++.h>
using namespace std;
int main(){
int t;
string s;
cin>>t;
while(t--){
cin>>s;
s=' '+s;
bool f1=false,f2=false;
int ans=1;
for(int i=2;i<s.size()-1;i++){
if(s[i]!=s[i-1]&&s[i]!=s[i+1]) f1=true;
else if(s[i]==s[i-1]&&s[i]==s[i+1]) f2=true;
}
ans+=f1+f2;
cout<<ans<<endl;
}
}
C. Subarrays #
Monocarp 有一个包含 \(n\) 个正整数的数组 \(a\)。他还有一个最喜欢的整数 \(k\)(\(k < n\))。
数组中索引从 \(l\) 到 \(r\)(\(1 \le l \le r \le n\))的连续元素序列被称为一个子数组。如果满足以下条件,Monocarp 称一个子数组是 \(k\)-平衡的(\(k\)-balanced):
- 子数组从 \(l\) 到 \(r\)(包含两端)的所有元素之和能被 \(k\) 整除;
- 这个子数组的长度严格大于 \(k\)(即 \(r - l + 1 > k\))。
请帮助 Monocarp 确定数组 \(a\) 中 \(k\)-平衡子数组的总数。
输入
第一行包含一个整数 \(t\)(\(1 \le t \le 10^4\))—— 测试用例的数量。
接下来是测试用例的描述。
每个测试用例的第一行包含两个整数 \(n\) 和 \(k\)(\(1 \le k < n \le 2 \cdot 10^5\))—— 数组 \(a\) 中的元素数量以及整数 \(k\)。
每个测试用例的第二行包含 \(n\) 个整数 \(a_1, a_2, \dots, a_n\)(\(1 \le a_i \le 10^9\))—— 数组 \(a\) 的元素。
关于输入的附加限制:
- 所有测试用例中 \(n\) 的总和不超过 \(2 \cdot 10^5\)。
输出
对于每个测试用例,输出一个整数 —— 数组 \(a\) 中 \(k\)-平衡子数组的数量。
考虑一下处理一个前缀和。那么 \(\sum_{i=x}^{y}a_i\equiv 0\pmod k\) 即为 \(s_{y}-s_{x-1}\equiv 0\pmod k\),\(s_{y}\equiv s_{x-1}\pmod k\)
#include<bits/stdc++.h>
using namespace std;
int n,k;
int cnt[200001],a[200001],s[200001];
int main(){
int t;cin>>t;
while(t--){
cin>>n>>k;
int ans=0;
for(int i=1;i<=n;++i){
cin>>a[i];
s[i]=s[i-1]+a[i];
cnt[s[i]%k]=0;
//cout<<s[i]%k<<" ";
}
//cout<<endl;
for(int i=1;i<=n;++i){
if(i-k-1>=0) cnt[s[i-k-1]%k]++;
ans+=cnt[s[i]%k];
}
cout<<ans<<endl;
}
}
D. Caveman #
Monocarp 画了一个包含 \(n\) 个顶点和 \(m\) 条边的无向图。他想将每个顶点染成红色或蓝色,使得每个顶点至少有一个颜色不同的邻居。他需要计算有多少种符合条件的染色方案。
Monocarp 是一个原始人:他只知道数字 \(1\)、\(2\) 和“许多”(任何大于 \(2\) 的数)。他不知道零的概念,所以如果没有任何合法的染色方案,他的大脑就会宕机。
请用 Monocarp 的语言帮助他统计合法的染色方案数。如果在至少一个顶点上颜色不同,则两个染色方案被视为不同的。
输入
第一行包含一个整数 \(t\)(\(1 \le t \le 10^4\))—— 测试用例的数量。
每个测试用例的第一行包含两个整数 \(n\) 和 \(m\)(\(3 \le n \le 3 \cdot 10^5\);\(0 \le m \le \min\left(\frac{n(n-1)}{2}, 3 \cdot 10^5\right)\))—— 顶点和边的数量。
接下来 \(m\) 行,每行包含两个整数 \(u_i\) 和 \(v_i\)(\(1 \le u_i, v_i \le n\))—— 第 \(i\) 条边连接的两个顶点的编号。图中没有自环或重边。
关于输入的附加限制:
- 所有测试用例中 \(n\) 的总和不超过 \(3 \cdot 10^5\);所有测试用例中 \(m\) 的总和也不超过 \(3 \cdot 10^5\)。
输出
对于每个测试用例,在单独的一行中输出:
1或2,如果合法染色方案的数量分别等于 1 或 2;Many,如果合法染色方案的数量大于 2;Brain Melt,如果没有合法的染色方案。
依旧脑筋急转弯这一块
一个一个考虑。先考虑方案为 \(0\) 的情况。可以发现仅当图不连通的时候可能无解。
方案为 \(1\) 的情况:不可能存在。证明:将合法方案取反,一定存在另一个解。或者说,方案数一定为偶数。
方案为 \(2\) 的情况:先考虑方案大于 \(2\) 的情况。设点 \(x,y\) ,假如 \(x\) 和 \(y\) 都有各自相邻的点 \(x_0,y_0\)。可以令 \(x_0=y_0,x=y\),也可以令 \(x_0=y,x=y_0\),结合对称性则至少有四种状态。如果 \(x_0,y_0\) 任一个不存在,那么不可能有 \(x=y\)。所以,如果我们想限制只存在 \(2\) 种方案,那么必须让任意两个点都不让 \(x_0,y_0\) 同时存在。也就是图的层数不超过 \(2\)。判断即可。
#include<bits/stdc++.h>
using namespace std;
int n,m;
vector<int>e[300001];
int vis[300001],d[300001];
int cnt;
void dfs(int u){
vis[u]=1;
cnt++;
for(auto v:e[u]){
if(vis[v]) continue;
dfs(v);
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int t;cin>>t;
while(t--){
cin>>n>>m;
for(int i=1;i<=n;++i){
vis[i]=0;
d[i]=0;
e[i].clear();
}
for(int i=1;i<=m;++i){
int u,v;
cin>>u>>v;
d[u]++,d[v]++;
e[u].push_back(v);
e[v].push_back(u);
}
int flag=0;
for(int i=1;i<=n;++i){
if(!vis[i]){
cnt=0;
dfs(i);
if(cnt==1){
flag=1;
break;
}
}
}
if(flag){
cout<<"Brain Melt"<<'\n';
continue;
}
flag=0;
int res=0;
for(int i=1;i<=n;++i){
if(d[i]==n-1) res++;
else if(d[i]!=1){
flag=1;
break;
}
}
if(flag||res!=1){
cout<<"Many"<<'\n';
continue;
}
cout<<2<<'\n';
}
}
E. Good Substrings #
给你一个长度为 \(n\) 的字符串 \(s\),仅由数字组成。
\(s\) 的子串是其字符的一个连续子序列。如果一个子串 \(s_{l \dots r}\) 包含字符串 2025 作为子序列,且不包含字符串 2026 作为子序列,则该子串是坏的。否则,该子串是好的。例如,字符串 2025、72707275、20625 是坏的,但字符串 20256、2026、777、1290723576 是好的。
对于从 \(1\) 到 \(n\) 的每个索引 \(i\),计算包含它的好子串的数量。换句话说,对于从 \(1\) 到 \(n\) 的每个索引 \(i\),计算整数对 \(l, r\) 的数量,使得 \(1 \le l \le i \le r \le n\) 且子串 \(s_{l \dots r}\) 是好的。
输入
第一行包含一个整数 \(t\)(\(1 \le t \le 10^4\))—— 测试用例的数量。
每个测试用例的第一行包含一个整数 \(n\)(\(1 \le n \le 3 \cdot 10^5\))。
第二行包含一个长度为 \(n\) 的字符串 \(s\),由数字组成。
关于输入的附加限制:所有测试用例中 \(n\) 的总和不超过 \(3 \cdot 10^5\)。
输出
对于每个测试用例,输出 \(n\) 个整数。第 \(i\) 个整数应等于包含索引 \(i\) 的好子串的数量。
考虑每个位置的坏字串个数。
肯定是要去找 2025 和 2026 第一次出现在哪里的。这个的话我们可以对每个位置 \(i\) 维护其后方第一个 2 在哪,同理维护 2 后面第一个 0,以此类推。设 2025,2026 的末位下标分别为 \(a,b\),那么当取 \([a,b-1]\) 内的字符串时,则是一个坏串。总的坏串数量是 \(b-a\)
不过答案要求区间答案。因此考虑一下差分。不过有一点需要注意的是,这样会把 \(a\) 前面的答案也统计进来。这个比较好处理,统计答案的时候减去 \(a\) 前面的累计差分就行了。最后,以 \(i\) 为左端点的总字串数量为 \(i(n-i+1)\),减一下就好了。
差分以后累计复杂度太高。直接用线段树维护前缀和即可。
cf爆炸了,代码等评测好了再粘

浙公网安备 33010602011771号