蓝桥杯a组 上海出线(AcWing – 蓝桥杯集训每日一题(DAY 1——DAY 5))
一 、AcWing 3956. 截断数组(中等)
题目描述
给定一个长度为
n
n
n 的数组a
1
,
a
2
,
…
,
a
n
a_{1},a_{2},…,a_{n}
a1,a2,…,an。
现在 ,要将该数组从中间截断 ,得到三个非空子数组 。
要求 ,三个子数组内各元素之和都相等 。
请问 ,共有多少种不同的截断方法?输入格式
第一行包含整数
n
n
n。
第二行包含n
n
n 个整数a
1
,
a
2
,
…
,
a
n
a_{1},a_{2},…,a_{n}
a1,a2,…,an 。输出格式
输出一个整数 ,表示截断方法数量 。
数据范围
前六个测试点满足:
1
≤
n
≤
10
1≤n≤10
1≤n≤10。
所有测试点满足:1
≤
n
≤
1
5
,
−
10000
≤
a
i
≤
10000
1≤n≤10^{5} ,−10000≤a_{i}≤10000
1≤n≤105 ,−10000≤ai≤10000 。输入样例 1
4
1 2 3 3输出样例 1
1
输入样例 2
5
1 2 3 4 5输出样例 2
0
输入样例 3
2
0 0输出样例 3
0
具体实现
1. 实现思路
我们有一个长度为 n 的数组 ,将其分成三段 ,使三段内的元素都相等 ,求有多少种截断方法 。 首先 ,我们可以先求解一些总和 s,如果 3 不可以整除总和 s 的话 ,就一定无解 。如果想要有解的话 ,s 一定是 3 的倍数 。因此,我们可以先计算出总和 s 和每一段的总和 s/3 。 问题就转变为一共有多少种选法 ,使得每一段的和都是 s/3。 我们可以先确定后面的点 ,让前面的总和是 2s/3 ,再选择前面的点 ,满足第一段是 s/3 。 我们再枚举的过程中 ,可以使用前缀和 ,计算出从起始点到每一段的前缀和 ,判断第一段前缀和是 s/3 ,第二段前缀和是 2s/3 即可 。2. 实现代码
#include <bits/stdc++.h> using namespace std; int n; int a[100005]; long long res=0,cnt=0; int main() { cin>>n; for(int i=1;i<=n;i++) { int x=0; cin>>x; a[i]=a[i-1]+x; //前缀和数组 } if(a[n]%3!=0 || n<3) { cout<<"0"<<endl; } else { for(int j=2;j<n;j++) { if(a[j-1]==a[n]/3) { cnt++; } if(a[j]==a[n]/3*2) { res+=cnt; } } cout<<res; } return 0; }二 、AcWing 3729. 改变数组元素(中等)
题目描述
给定一个空数组
V
V
V 和一个整数数组a
1
,
a
2
,
…
,
a
n
a_{1},a_{2},…,a_{n}
a1,a2,…,an。
现在要对数组V
V
V 进行n
n
n次操作 。
第i
i
i 次操作的具体流程如下: 从数组V
V
V 尾部插入整数 0 。 将位于数组V
V
V 末尾的a
i
a_{i}
ai 个元素都变为1
1
1(已经是1
1
1 的不予理会) 。注意:
a
i
a_{i}
ai 可能为 0 ,即不做任何改变 。a
i
a_{i}
ai 可能大于目前数组 V 所包含的元素个数 ,此时视为将数组内所有元素变为1
1
1。
请你输出所有操作完成后的数组V
V
V 。输入格式
第一行包含整数
T
T
T ,表示共有T
T
T组测试数据 。
每组数据第一行包含整数n
n
n。
第二行包含n
n
n 个整数a
1
,
a
2
,
…
,
a
n
a_{1},a_{2},…,a_{n}
a1,a2,…,an 。输出格式
每组数据输出一行结果 ,表示所有操作完成后的数组
V
V
V,数组内元素之间用空格隔开 。数据范围
1
≤
T
≤
20000
1≤T≤20000
1≤T≤200001
≤
n
≤
2
×
1
5
1≤n≤2×10^{5}
1≤n≤2×105≤
a
i
≤
n
0≤a_{i}≤n
0≤ai≤n 保证一个测试点内所有n
n
n 的和不超过2
×
1
5
2×10^{5}
2×105 。输入样例
3
6
0 3 0 0 1 3
10
0 0 0 1 0 5 0 0 0 2
3
0 0 0输出样例
1 1 0 1 1 1
0 1 1 1 1 1 0 0 1 1
0 0 0具体实现
1. 实现思路
由于我们每次操作都会加入一个数 ,在操作 i 次之后 ,新数组的长度就是 i,然后 ,再将当前数组的最后面的 ai 个数变成 1 。 由于第 i 次数组一共有 i 个 ,将后 ai 个数变为 1 ,也就是我们将是 i-ai+1 到 i 的区间内的 ai 个数全部变成 1 ,也就是这个区间内的数据操作一次。 因此 ,我们可以开一个新数组与原数组长度相等 ,用以记录区间内数据操作的个数 ,因为 V 数组当中的 1 不会发生改变 ,所以 ,操作多次和操作一次的效果是相同的 。 最后 ,如果新数组当中的元素大于 0 ,那么 V 数组中对应的元素就是 1 ,如果新数组中的元素等于 0,那么 V 数组中对应的元素就是 0 。2. 实现代码
#include <bits/stdc++.h> using namespace std; const int N=200010; int n; int b[N]; int main() { int T; cin>>T; while(T--) { cin>>n; memset(b,0,(n+1)*4); for(int i=1;i<=n;i++) { int x; cin>>x; x=min(x,i); //如果x大于i的话就更新成i ,因为此时是将数组内的所有元素变为1 int l=i-x+1,r=i; b[l]++;b[r+1]--; } for(int i=1;i<=n;i++) { b[i]+=b[i-1]; } for(int i=1;i<=n;i++) { cout<<!!b[i]<<" "; } cout<<endl; } return 0; }三 、AcWing 1460. 我在哪?(简单)
题目描述
农夫约翰出门沿着马路散步 ,但是他现在发现自己可能迷路了!
沿路有一排共N
N
N个农场。
不幸的是农场并没有编号,这使得约翰难以分辨他在这条路上所处的位置 。
然而 ,每个农场都沿路设有一个彩色的邮箱 ,所以约翰希望能够通过查看最近的几个邮箱的颜色来唯一确定他所在的位置 。
每个邮箱的颜色用A
.
.
Z
A..Z
A..Z 之间的一个字母来指定 ,所以沿着道路的N
N
N 个邮箱的序列可以用一个长为N
N
N 的由字母A
.
.
Z
A..Z
A..Z组成的字符串来表示 。
某些邮箱可能会有相同的颜色 。
约翰想要知道最小的K
K
K 的值 ,使得他查看任意连续K
K
K个邮箱序列 ,他都可以唯一确定这一序列在道路上的位置 。
例如 ,假设沿路的邮箱序列为 ABCDABC 。
约翰不能令K
=
3
K=3
K=3,因为如果他看到了 ABC ,则沿路有两个这一连续颜色序列可能所在的位置 。
最小可行的K
K
K 的值为K
=
4
K=4
K=4 ,因为如果他查看任意连续4
4
4 个邮箱 ,那么可得到的连续颜色序列可以唯一确定他在道路上的位置 。输入格式
输入的第一行包含
N
N
N ,第二行包含一个由N
N
N 个字符组成的字符串 ,每个字符均在A
.
.
Z
A..Z
A..Z 之内 。输出格式
输出一行,包含一个整数 ,为可以解决农夫约翰的问题的最小
K
K
K 值 。数据范围
1
≤
N
≤
100
1≤N≤100
1≤N≤100输入样例
7
ABCDABC输出样例
4
具体实现
1. 实现思路
我们要找到一个最小的 K ,使得字符串当中从 K 分开不存在两个相同的字符串 。 我们可以使用暴力解法,也就是 4 个 for 循环 ,第一重循环枚举每一个 K ,第二重循环枚举第一个子串 ,第三重循环枚举第二个子串 ,第四重循环判断两个字串是否相同 。2. 实现代码
#include <bits/stdc++.h> using namespace std; int n; string str; int main() { cin >> n >> str; for (int k = 1; k <= n; k ++ ) { bool flag = false; for (int i = 0; i + k - 1 < n; i ++ ) { for (int j = i + 1; j + k - 1 < n; j ++ ) { bool same = true; for (int u = 0; u < k; u ++ ) if (str[i + u] != str[j + u]) { same = false; break; } if (same) { flag = true; break; } } if (flag) break; } if (!flag) { cout << k << endl; break; } } return 0; }四 、AcWing 3768. 字符串删减(简单)
题目描述
给定一个由
n
n
n个小写字母构成的字符串。
现在 ,需要删掉其中的一些字母 ,使得字符串中不存在连续三个或三个以上的x
x
x。
请问 ,最少需要删掉多少个字母?
如果字符串本来就不存在连续的三个或三个以上x
x
x ,则无需删掉任何字母 。输入格式
第一行包含整数
n
n
n。
第二行包含一个长度为n
n
n 的由小写字母构成的字符串 。输出格式
输出最少需要删掉的字母个数 。
数据范围
3
≤
n
≤
100
3≤n≤100
3≤n≤100输入样例 1
6
xxxiii输出样例 1
1
输入样例 2
5
xxoxx输出样例 2
0
输入样例 3
10
xxxxxxxxxx输出样例 3
8
具体实现
1. 实现思路
我们利用 cnt 存储当前连续出现字符 x 的个数 。 若出现了一个字符 x ,则 cnt 加一 。 若出现了一个其它字符 ,则 cnt 清零 。 若当前 cnt=3 ,说明遇到了连续三个 x ,此时需要删除一次 。特别地,此时删除最后一个字符 x 后 ,可能补位的字符仍为 x ,如输入样例 3 所示 。此时不能将 cnt 清零,而应该减一 ,然后继续遍历 。2. 实现代码
#include <bits/stdc++.h> using namespace std; int main() { int n; string s; cin>>n>>s; int res=0,cnt=0; for(int i=0;i<n;i++) { if(s[i]==x) { cnt++; if(cnt==3) { cnt--; res++; } } else { cnt=0; } } cout<<res<<endl; return 0; }五 、AcWing 3777. 砖块(简单)
题目描述
n
n
n 个砖块排成一排 ,从左到右编号依次为1
∼
n
1∼n
1∼n。
每个砖块要么是黑色的 ,要么是白色的 。
现在你可以进行以下操作若干次(可以是 0次):
选择两个相邻的砖块 ,反转它们的颜色 。(黑变白 ,白变黑)
你的目标是通过不超过3
n
3n
3n 次操作 ,将所有砖块的颜色变得一致 。输入格式
第一行包含整数
T
T
T ,表示共有T
T
T组测试数据。
每组数据第一行包含一个整数n
n
n。
第二行包含一个长度为n
n
n 的字符串s
s
s 。其中的每个字符都是 W 或 B ,如果第i
i
i 个字符是 W ,则表示第i
i
i 号砖块是白色的 ,如果第i
i
i 个字符是 B ,则表示第i
i
i 个砖块是黑色的。输出格式
每组数据 ,如果无解则输出一行
−
1
−1
−1。
否则,首先输出一行k
k
k,表示需要的操作次数 。
如果k
>
k>0
k>0 ,则还需再输出一行k
k
k 个整数,p
1
,
p
2
,
…
,
p
k
p_{1},p_{2},…,p_{k}
p1,p2,…,pk 。其中p
i
p_{i}
pi 表示第i
i
i 次操作 ,选中的砖块为p
i
p_{i}
pi 和p
i
+
1
p_{i+1}
pi+1号砖块 。
如果方案不唯一 ,则输出任意合理方案即可 。数据范围
1
≤
T
≤
10
1≤T≤10
1≤T≤102
≤
n
≤
200
2≤n≤200
2≤n≤200输入样例
4
8
BWWWWWWB
4
BWBB
5
WWWWW
3
BWB输出样例
3
6 2 4
-1
0
2
2 1具体实现
1. 实现思路
并没有要求操作次数最少 ,因此 ,只需输出任意一组可成功操作的次数即可 。最终的结果只有两种 ,要么全黑 ,要么全白 , 两种情况可以依次枚举(任一情况都可) 。 同一个位置我们最多操作 1 次 ,因为操作两次的话就变回原样 。并且 ,操作的顺序不影响最后的结果 。 其中 ,第一个砖块只能操作一次 ,所以 ,如果第一个砖块跟我们目标颜色相同的话,就不需要进行操作 ,如果不同的话 ,就一定会进行操作 。第一个砖块是否操作是已经确定的了,第二个砖块也是同样的道理 ,后续皆同 。因此在最后 ,如果最后一个砖块和目标颜色相同的话 ,就一定有解 ,如果不同的话就一定无解 ,这中间我们只需要操作 n-1 次 。2. 实现代码
#include <bits/stdc++.h> using namespace std; int n; string str; void update(char &c) { if(c==W) { c=B; } else { c=W; } } bool check(char c) { vector<int>res; string s=str; for(int i=0;i<n-1;i++) { if(s[i]!=c) { update(s[i]); update(s[i+1]); res.push_back(i+1); //字符串从0开始 ,题目中从1开始 } } if(s.back()!=c) { return false; } cout<<res.size()<<endl; for(int x=0;x<res.size();x++) { cout<<res[x]<<; } if(res.size()!=0) { cout<<endl; } return true; } int main() { int T; cin>>T; while(T--) { cin>>n>>str; if(!check(B)&&!check(W)) { cout<<"-1"<<endl; } } return 0; }创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!