Codeforces Round #741 (Div. 2) A~D1题解
文章目录
A. The Miracle and the Sleeper
-
题意
给定 l , r l,r l,r,找出 a , b ( l ≤ b ≤ a ≤ r ) a,b(l\leq b\leq a\leq r) a,b(l≤b≤a≤r)使得 a m o d b a\mod b amodb最大。 -
解题思路
我们知道,如果要让余数,最大,就要尽可能的让 a a a最大,且 b b b取 a / 2 + 1 a/2 + 1 a/2+1。这样的余数就是我们能取到的最大值。 a a a最大即为 r r r,那么如果 b = r / 2 + 1 < l b=r/2+1<l b=r/2+1<l我们该怎么办呢?由于往后的余数都为 a − b a-b a−b,所以我们让 b b b取最小值即可,即为 l l l,故此题易解。 -
AC代码
/**
*@filename:A_The_Miracle_and_the_Sleeper
*@author: pursuit
*@created: 2021-08-26 22:35
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int t,l,r;
//l <= b <= a <= r
void solve(){
int x = max(l, r / 2 + 1);
cout << r % x << endl;
}
int main(){
cin >> t;
while(t -- ){
cin >> l >> r;
solve();
}
return 0;
}
B. Scenes From a Memory
-
题意
给定一个整数 n n n,问你能删除最多多少位的数使得删除后的数为合数。 -
解题思路
由于要尽量多的删除,所以易得 1 , 4 , 6 , 8 , 9 1,4,6,8,9 1,4,6,8,9一定满足,即如果出现了这些数我们就可以选择只留一个删掉其余的数即可。
倘若不能存在这些数的话,那么我们留的数的位数也至少会存在两位。我们继续分析,既然存在两位,那么如果一个数出现了 1 1 1次以上,那么我们就可以选择这个数 i i i构成 i i ii ii,这样它会存在一个因子为 11 11 11,即为合数,这种也是最优的。
经过上述分析,最后还有一种情况为考虑,就是 2 , 3 , 5 , 7 2,3,5,7 2,3,5,7这几个数,且只单独出现了最多一次。我们特判处理即可。如果 2 2 2和 5 5 5前面有数,那么一定存在 x 2 , x 5 x2,x5 x2,x5这种合数,对于 7 7 7有 57 , 27 57,27 57,27。对于 3 3 3,其不能最优构成合数( 573 573 573等价于 57 57 57)。
至此即可解决此题。 -
AC代码
/**
*@filename:B_Scenes_From_a_Memory
*@author: pursuit
*@created: 2021-08-26 22:42
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int t,k;
string s;
void solve(){
map<char,int> p;
for(int i = 0; i < s.size(); ++ i){
p[s[i]] ++;
if(s[i] == '1'){
cout << 1 << '\n' << 1 << endl;
return;
}
else if(s[i] == '4'){
cout << 1 << '\n' << 4 << endl;
return;
}
else if(s[i] == '6'){
cout << 1 << '\n' << 6 << endl;
return;
}
else if(s[i] == '8'){
cout << 1 << '\n' << 8 << endl;
return;
}
else if(s[i] == '9'){
cout << 1 << '\n' << 9 << endl;
return;
}
}
for(char i = '1'; i <= '9'; ++ i){
if(p[i] > 1){
cout << 2 << '\n' << i << i << endl;
return;
}
}
p.clear();
//只有2357,且最多不会超过4个。
for(int i = 0; i < s.size(); ++ i){
if(s[i] == '2' && i != 0){
cout << 2 << '\n' << s[i - 1] << 2 << endl;
return;
}
else if(s[i] == '7' && p['2']){
cout << 2 << '\n' << 2 << 7 << endl;
return;
}
else if(s[i] == '5' && i != 0){
cout << 2 << '\n' << s[i - 1] << 5 << endl;
return;
}
else if(s[i] == '7' && p['5']){
cout << 2 << '\n' << 57 << endl;
return;
}
else
p[s[i]] ++;
}
}
int main(){
cin >> t;
while(t -- ){
cin >> k >> s;
solve();
}
return 0;
}
C. Rings
-
题意
给你一个 n n n位二进制数。需要你找到两个区间 [ l 1 , r 1 ] , [ l 2 , r 2 ] ( r 1 − l 1 + 1 ≥ ⌊ n 2 ⌋ , r 2 − l 2 + 1 ≥ ⌊ n 2 ⌋ ) [l_1,r_1],[l_2,r_2](r_1-l_1+1\geq \lfloor\frac{n}{2}\rfloor,r_2-l_2+1\geq \lfloor\frac{n}{2}\rfloor) [l1,r1],[l2,r2](r1−l1+1≥⌊2n⌋,r2−l2+1≥⌊2n⌋),使得前者截取二进制位构成的数为后者截取二进制位构成的数的倍数。 -
解题思路
我们考虑二进制中的 0 0 0,如果 0 0 0后面有 ⌊ n 2 ⌋ \lfloor\frac{n}{2}\rfloor ⌊2n⌋的位,那么我们可以构造出 0 x 0x 0x和 x x x, x x x为从 0 0 0后面截取的二进制串。这样两者是相等的,即满足条件;如果 0 0 0前面有 ⌊ n 2 ⌋ \lfloor\frac{n}{2}\rfloor ⌊2n⌋的位,那么我们可以构造出 x 0 x0 x0和 x x x, x x x为从 0 0 0前面截取的二进制串。
这样前者为后者的两倍,即满足条件。
根据以上分析,只要存在 0 0 0,经过以上构造就一定满足条件。那如果没有 0 0 0呢?我们可以选择长度相等端点不同的构造,这样值是相等的,也同样满足条件。
故此题得解。 -
AC代码
/**
*@filename:C_Rings
*@author: pursuit
*@created: 2021-08-26 23:25
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 2e4 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*
0代表金,1代表银
*/
int t,n;
char s[N];
void solve(){
for(int i = 1; i <= n; ++ i){
if(s[i] == '0' && n - i >= n / 2){
printf("%d %d %d %d\n", i, n, i + 1, n);
return;
}
else if(s[i] == '0' && i - 1 >= n / 2){
printf("%d %d %d %d\n", 1, i, 1, i - 1);
return;
}
}
//说明不存在0.
printf("%d %d %d %d\n", 1, n / 2, 2, n / 2 + 1);
}
int main(){
scanf("%d", &t);
while(t -- ){
scanf("%d%s", &n, s + 1);
solve();
}
return 0;
}
D1. Two Hundred Twenty One (easy version)
-
题意
给你一个二进制串,其中 包含+,-
两种字符,+
代表 1 1 1,-
代表 − 1 -1 −1。给定区间 [ l , r ] [l,r] [l,r],问需要删除最多多少位数使得 ∑ i = l n ( − 1 ) i − 1 a i = 0 \sum_{i=l}^n(-1)^{i-1}a_i=0 ∑i=ln(−1)i−1ai=0。 -
解题思路
我们知道,对于 a i a_i ai要么为 1 1 1要么为 − 1 -1 −1,对于其前面的 ( − 1 ) i − 1 (-1)^{i-1} (−1)i−1也决定了符号位。
如果区间长度为奇数,那么我们肯定是要删除的。由于删除一个位置可以使得后面的都变更符号,且当前位置的贡献消失,那么我们可以证明我们只需要删除一位即可实现和为 0 0 0。这是为什么呢?因为删除一位可以弥补区间长度和本身产生的 1 1 1,而如果有其他多余的我们可以选择其具体数值来选定位置删除然后根据后面的符号变更来抵消。
那么如果区间长度为偶数,我们删除也要使得其为区间长度保持为偶数。再具体分析,如果这一段的和为 0 0 0,那么我们肯定是不用删除的,如果不为 0 0 0呢?其实同区间长度为奇数分析一样,我们可以自由选择删除位置,所以我们总能找到位置使得后面符号位变更来抵消多出的数值,由于区间长度需为偶数,所以我们需要删除两个位置。
那么怎么求区间长度和呢?我们可以利用前缀和预处理得到,我这里采用了两个数组求前缀和,因为 l l l决定了他在原数组中是奇数还是偶数。
故此题得解。 -
AC代码
/**
*@filename:D1_Two_Hundred_Twenty_One_easy_version_
*@author: pursuit
*@created: 2021-08-26 23:57
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 3e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int t,n,q;
char s[N];
int sum1[N],sum2[N];
void solve(){
for(int i = 1; i <= n; ++ i){
if(i & 1){
sum1[i] = sum1[i - 1] + (s[i] == '+' ? 1 : -1);
sum2[i] = sum2[i - 1] - (s[i] == '+' ? 1 : -1);
}
else{
sum1[i] = sum1[i - 1] - (s[i] == '+' ? 1 : -1);
sum2[i] = sum2[i - 1] + (s[i] == '+' ? 1 : -1);
}
}
int l,r;
while(q -- ){
scanf("%d%d", &l, &r);
if((r - l + 1) & 1){
puts("1");
}
else if(l & 1){
if(sum1[r] - sum1[l - 1]){
puts("2");
}
else{
puts("0");
}
}
else{
if(sum2[r] - sum2[l - 1]){
puts("2");
}
else{
puts("0");
}
}
}
}
int main(){
scanf("%d", &t);
while(t -- ){
scanf("%d%d", &n, &q);
scanf("%s", s + 1);
solve();
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具