第一题:送分题!
由程序设计协会(CPA)举办的一年一度程序设计团体赛它来了!为了让同学们感受程序设计的魅力,yang学长在这里给大家送福利了!
输入格式:
本题无输入。
输出格式:
请看输出样例。
输入样例:
无
输出样例:
CPA666!
该题就是签到题,直接输出CPA666!即可。
#include<bits/stdc++.h>
using namespace std;
int main(){
cout<<"CPA666!";
return 0;
}
第二题:年月日。
世界上不同国家有不同的写日期的习惯。
输入格式:
输入在一行中按照“m/d/y”的格式给出月、日、年。
输出格式:
输出在一行中按照“y/m/d”的格式给出年、月、日。
输入样例:
3/30/2024
输出样例:
2024/03/30
该题是个简单模拟,按照题目意思输出即可。
#include<bits/stdc++.h>
using namespace std;
int main(){
int a,b,c;
scanf("%d/%d/%d",&b,&c,&a);
printf("%d/%02d/%02d",a,b,c);
return 0;
}
第三题:火眼金睛
考验同学们眼力的时候到了。
“ABCDEFGIJKMNOPRSTUVWXYZ”。
引号里原有26个大写字母,按顺序、无重复的排列着,现在请你找出缺失的字母然后按顺序直接输出。
输入格式:
本题无输入。
输出格式:
无
输入样例:
无
输出样例:
无
该题数字母就行,签到题
#include<bits/stdc++.h>
using namespace std;
int main(){
cout<<"HLQ";
return 0;
}
第四题:1!5!
小珍觉得义务对一个人来说很重要。向来运气很好的他每天都会对自己大喊“义!务!”。久而久之,15便成了小珍的幸运数。在某天他突发奇想,想快速判断某个数是不是自己的幸运数,但是他并不会编程,聪明的你能帮帮他吗?
判断某些数是不是15的倍数。数据范围-2^100<x<2^100
输入格式:
第一行给出一个t,代表有t组测试用例,接下来t行,每行给出一个数,1≤t≤1000。
输出格式:
对于每组测试用例,如果这个数是15的倍数,输出“yes”,否则输出“no”。
输入样例:
在这里给出一组输入。例如:
2
15
31
输出样例:
在这里给出相应的输出。例如:
yes
no
该题是到数学规律题,15的可以分为3,5这两个素数的乘积,即只要满足是3的倍速和是5的倍数,这个数就是15的倍数。由于是大数据,需要用字符串来输入。
#include<bits/stdc++.h>
using namespace std;
int main() {
int t;
cin >> t;
while(t--) {
string s;
int cnt = 0;
cin >> s;
for(int i = 0; i < s.size(); i++) {
if(s[i] == '-') continue;
cnt += (s[i] - '0');
}
if(cnt % 3 == 0 && (s[s.size() - 1] == '0' || s[s.size() - 1] == '5'))
cout << "yes\n";
else
cout << "no\n";
}
return 0;
}
第五题:判断大小等
给出x,y,判断(x^2 + y^2)/2 和162 - x*y的关系 ,输出”>”或者“=”或者“<”
输入格式:
输入在一行中给出2个长度不超过100的整数A和B,用空格分隔。
输出格式:
在一行中输出这两者的关系,即“>”或“<”或“=”。
输入样例:
0 0
输出样例:
<
该题是一道数学题,化简如下
#include<bits/stdc++.h>
using namespace std;
int main()
{
int a,b;
cin>>a>>b;
if((pow(a,2)+pow(b,2))/2>162-a*b) cout<<'>';
else if((pow(a,2)+pow(b,2))/2==162-a*b) cout<<'=';
else cout<<'<';
return 0;
}
第六题:找次数
给出两个非空字符串x, y。找出字符串y在字符串x中出现的次数,x,y只包含英文字符
输入格式:
输入有两行。
第一行给出字符串x,第二行给出字符串y。
输出格式:
在一行中输出字符串y在字符串x中出现的次数。
输入样例:
cpacpacpa
cpa
输出样例:
3
该题考查对字符串中find函数以
及erase函数的使用。对于这道题,我们先判断x里面是否有y字符串,有,则计数器加一,然后在更新一下x字符串长度,即从上一次查到y字符串的下标开始查找y。
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
using namespace std;
int main(void){
IOS;
string x, y;
cin>>x>>y;
int ans=0;
while(x.find(y)!=-1){
int id=x.find(y);
x.erase(id,y.size());
ans++;
}
cout<<ans<<'\n';
return 0;
}
第七题:学长与他的字符串
在寝室里面,倪学长因为太无聊了,自己玩起了一个游戏,游戏名是字符串反转,他在纸上写了一个字符串,然后进行n次操作,操作规则如下:
1、反转当前字符串;
2、在当前字符串前面加上输入的这个字符串;
3、在当前字符串后面加上输入的这个字符串;
4、查找在当前字符串中是否存在输入的这个字符串,诺有则输出Yes,否则输出No。
当n的次数越大,倪学长手写的越累,于是他向各位同学求助。所以,同学你能帮助一下倪学长吗?最后记得把最后的字符串输出给倪学长看一下哦。
输入格式:
第一行是一个字符串s,字符串内只有大小写字母
第二行是n次操作(1<=n<=1e2)
接下来是n行,每行先读入一个整数op(1<=op<=4):
-
若op=1,反转当前字符串;
-
若op=2、在当前字符串前面加上输入的这个字符串;
-
若op=3、在当前字符串后面加上输入的这个字符串;
-
若op=4、查找在当前字符串中是否存在输入的这个字符串,诺有则输出Yes,否则输出No。
输出格式:
当op=4时,输出Yes或No,每个结果占一行,最后一行输出完成所有操作的字符串。
输入样例:
pc
3
1
3 a
4 cpa
输出样例:
Yes
cpa
该题就是一个字符串的模拟,当op=1时,将字符串反转,当op=2时,在当前字符串前面加上输入的这个字符串,当op=3时,在当前字符串后面加上输入的这个字符串。
按照这个模拟即可
#include<bits/stdc++.h>
using namespace std;
// string huan(string s) {
// string s1 = "";
// for(int i = s.size() - 1; i >= 0; i--)
// s1 += s[i];
// return s1;
// }
int main() {
string s;
cin >> s;
int t;
cin >> t;
while(t--) {
int op;
cin >> op;
// if(op == 1) s = huan(s);
if(op == 1) reverse(s.begin(),s.end());
//reverse可以换成上面那个函数,两者都对
else if(op == 2) {
string s1;
cin >> s1;
s1 += s;
s = s1;
}
else if(op == 3) {
string s1;
cin >> s1;
s += s1;
}
else {
string s1;
cin >> s1;
int it = s.find(s1);
if(it >= 0) cout << "Yes\n";
else cout << "No\n";
}
}
cout << s << endl;
return 0;
}
第八题:统计次数
曾经,在一座古色古香的小镇上,有一家宁静而温馨的双人小旅馆。杰克是这家旅馆的慈祥老板,每天都在忙碌地登记着前来入住的客人。随着时间的推移,杰克发现有些租客会多次出现在他的记录中,尽管他并不总是按照相同的顺序记录他们的名字。面对这种情况,杰克开始思考如何统计某段时间内进入旅馆次数最多的那组客人的进入次数。这个小小的难题成为了他日常琐事中的一抹乐趣。
数据范围:1≤N≤1000
输入格式:
第一行包含整数 N。接下来 N 行,每行都包含一组租客的名字,每组租客只包含两个人,每个名字都是一个长度在 1∼10之间的由小写字母构成的字符串。
输出格式:
输出进入旅馆次数最多的一组租客的进入次数。
输入样例:
在这里给出一组输入。例如:
4
alice bob
bob alice
bob alice
coc dod
输出样例:
在这里给出相应的输出。例如:
3
该题的题意就是给出一组字符串,让你求那组字符串出现次数最多即使用map函数。该题需要注意的点就是这一组字符串中,x+y与y+x是同一组。即我们就多判断y+x字符串就行了。
#include<bits/stdc++.h>
using namespace std;
int main() {
int t;
cin >> t;
int maxx = 0;
map<string,int> m;
while(t--) {
string x, y;
cin >> x >> y;
string s1, s2;
s1 = x + y;
s2 = y + x;
m[s1]++;
m[s2]++;
maxx = max(maxx,max(m[s1],m[s2]));
}
cout << maxx << endl;
return 0;
}
第九题:推箱子
都玩过推箱子吧,那么这个题一定难不倒聪明的你!不跟你们多啰嗦,直接上干货!
1表示墙 0表示没有障碍物的路 2表示箱子 6表示箱子应该放置的位置(箱子不做区分)
移动方向:
1表示向上
2表示向右
3表示向下
4表示向左
下标从1开始^_^(看清楚哦!)
输入格式:
第一行输入N,M (5<=N,M<=15)。表示这是一个N*M的推箱子地图
第二行输入人物当前的位置
随后N行M列为推箱子地图
接着输入K,随后输入K次人物的移动方向
(每次只移动一格,移动方向只有上,下,左,右,数据保证已经归位的箱子不会被再次推出)
输出格式:
第一行输出人物当前所在的位置x y
第二行输出未归位箱子的数量(没有则输出0)
输入样例
9 9
5 5
1 1 1 1 1 1 1 1 1
1 1 1 1 6 1 1 1 1
1 1 1 1 0 1 1 1 1
1 1 1 1 2 1 1 1 1
1 6 2 0 0 0 2 6 1
1 1 1 1 0 1 1 1 1
1 1 1 1 2 1 1 1 1
1 1 1 1 6 1 1 1 1
1 1 1 1 1 1 1 1 1
13
1 1 3 3 3 3 1 1 2 2 4 4 4
输出样例:
5 4
1
该题就是一个大模拟题,使用二维数组模拟,按照题意的意思模拟就行,注意点:箱子可能会撞墙,还有推没推到箱子。
#include<bits/stdc++.h>
using namespace std;
int a[16][16];
// 上 -1 0
// 右 0 1
// 下 1 0
// 左 0 -1
int dx[5]={0,-1,0,1,0},dy[5]={0,0,1,0,-1};
int n,m,k,x,y,op,cnt;
void move(int c){
if(a[x+dx[c]][y+dy[c]]!=1){//如果人物下一次的落点不是墙
x+=dx[c]; y+=dy[c];//不是墙的话人物移动
//既然落点不是墙,就只剩推到箱子和没推到箱子两种情况。
if(a[x][y]==2){//如果推到了箱子,就看箱子的落点会不会撞墙。
if(a[x+dx[c]][y+dy[c]]!=1){//如果没撞墙,那么正常推动。
a[x][y]=0;//箱子推动前的位置变成路
a[x+dx[c]][y+dy[c]]=2;//将箱子移动到落点位置
}else{//如果撞墙了,那么人物和箱子的位置都不改变。
x-=dx[c]; y-=dy[c];//由于上面人物已经移动,所以就让人物退回原位。
}
}
}
}
int main()
{
cin>>n>>m;
cin>>x>>y;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>a[i][j];
cin>>k;
while(k--){
cin>>op;
move(op);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(a[i][j]==6) cnt++;
cout<<x<<' '<<y<<'\n'<<cnt;
return 0;
}
第十题:五子棋
张学长和孙学长最近迷上了五子棋,但是看着棋局下棋总感觉差点什么东西——高手的风范,于是两人就开始下盲棋,但是两人的脑阔都不是太灵光,没办法记下所有的落子,所以就先写下落子的坐标后再去棋盘落子,最后才知道是那个获胜,这里将棋盘看成是一个N*N (N=20) 的二维矩阵,刚开始时通过摇骰子的方式决定那个先手(点数大的先手,不存在点数相等的情况),每一次落子都是(i ,j)1<=i,j<=20 表示落子的坐标,问经过M(9<=M<=60)次落子后是未分输赢还是有赢方,由于两人刚开始下盲棋,所以不知道到底有没有人获胜,所以哪怕有一方已经获胜了也还会继续下棋,当两人都感觉到有一方获胜后才会停止下棋(也可能会感觉错^_^)。
输入格式:
第一行输入A,B分别表示张学长的点数和孙学长的点数
第二行输入M。接下来M行每行输入一个落子的坐标。
输出格式:
如果未分输赢只需要输出Draw
即可,否则就先输出赢家的编号(张学长编号为A
,孙学长编号为B
)空格后输出赢家落了多少棋子就赢了。
输入样例:
1 6
12
6,10
5,11
7,11
6,12
5,9
7,13
8,12
8,14
4,8
9,13
4,10
9,15
输出样例:
B 5
该题主要考察递归。
想要跟详细请看:https://blog.csdn.net/dark__matter_/article/details/137123447
#include<bits//stdc++.h>
using namespace std;
int k[21][21];
bool isOk(int i,int j){//判断下标是否越界
if(i>=1&&i<=20&&j>=1&&j<=20) return true;
return false;
}
// 1 2
// // 上 1 0
// // 下 -1 0
// 3 4
// // 左 0 -1
// // 右 0 1
// 5 6
// // 右上 -1 1
// // 左下 1 -1
// 7 8
// // 左上 -1 -1
// // 右下 1 1
//对于五子棋来说,我们只需要即时搜索当前的落子能不能
//与之前的落子在某一条直线上是不是有5子相连就行
int dx[9]={0,1,-1,0,0,-1,1,-1,1};
int dy[9]={0,0,0,-1,1,1,-1,-1,1};
int sameTotal(int x,int y,int c,int op){
//op为棋子类型,c为递归方向,这里的递归方向看上面的dx[]和dy[]数组
//看完就知道递归的方向是什么了。
x+=dx[c];y+=dy[c];//向判断方向移动一格
if(isOk(x,y)&&k[x][y]==op) return sameTotal(x,y,c,op)+1;//如果没越界,且棋子相同,递归在深入一层
else return 0;//否则就终止递归并带值返回调用源头
}
int isWin(int x,int y,int op){
int sum,maxn=-1;
for(int i=1;i<=7;i+=2){//一共八个方向,但是五子棋是看的一条直线,所以成对递归。
sum=sameTotal(x,y,i,op)+sameTotal(x,y,i+1,op);
maxn=max(maxn,sum);
if(maxn==4) break;
}
return maxn+1;
}
int main()
{
int A,B,a=0,b=0,M,i,j,f=1;
cin>>A>>B>>M;
if(A<B) f=0;
while(M--){
scanf("%d , %d",&i,&j);
if(f%2){
k[i][j]=1;
a++;
if(isWin(i,j,1)>=5){
cout<<"A "<<a;
return 0;
}
}else{
k[i][j]=-1;
b++;
if(isWin(i,j,-1)>=5){
cout<<"B "<<b;
return 0;
}
}
f++;
}
cout<<"Draw";
return 0;
}
第十一题:副会长的手机游戏有锁
倪会长最近迷上了手机游戏,为了学习,倪会长决定,给游戏上锁,但是又不能自己来上锁,要不然就掩耳盗铃了。所有倪会长让他的朋友给他上了锁。
在一个风雨交加的夜晚,倪会长实在忍不住了,就去打开了那个手机游戏,游戏页面突然冒出了一个方程:ax^2+bx+c=0,后面有者一堆数据。倪会长傻眼了。
输入格式:
第一行给出一个t,代表有t组测试用例(1<=t<=100)。
每一组测试用例给出n和x,分别代表有n个整数和x的值
下面一行n个整数
1<=n<=100,x<=100;
-1000<=a[i]<=1000;
输出格式:
对于每一组测试用例,问这n个整数中是否存在三个数a,b,c使得ax^2+bx+c=0,数字可以重复使用。
输出描述,对于每一组测试用例,请输出Yes或者No,每个输出占一行。
输入样例::
1
1 15
0
输出样例:
Yes
该题可以暴力直接过,但是建议还是使用二分
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
int t;
cin >> t;
while(t--) {
int n, x;
cin >> n >> x;
int a[n];
for(int i = 0; i < n; i++) cin >> a[i];
int f1 = 0;
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
int f2 = 0;
for(int k = 0; k < n; k++) {
ll sum = a[i] * x * x + a[j] * x + a[k];
if(sum == 0) {
f2 = 1;
break;
}
}
if(f2 == 1) {
f1 = 1;
break;
}
}
if(f1 == 1) break;
}
if(f1 == 1) cout << "Yes\n";
else cout << "No\n";
}
return 0;
}
该题主要考察二分查找模板题,在二分查找前,需记得先排序。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main() {
int t;
cin >> t;
while(t--) {
ll m, n, x, y, ans;
int f = 0;
cin >> n >> x;
ll a[10050];
for (int i = 1; i <= n; i++)
cin >> a[i];
sort(a + 1, a + 1 + n);
for (int i = 1; i <= n; i++) {
ans = a[i] * x * x;
for (int j = 1; j <= n; j++) {
y = a[j] * x;
int l = 1, r = n;
while (l <= r) {
int mid = (l + r) / 2;
if (ans + y + a[mid] == 0) {
cout << "Yes\n";
f = 1;
break;
}
else if (ans + y + a[mid] < 0) {
l = mid + 1;
}
else
r = mid - 1;
}
if(f == 1) break;
}
if(f == 1) break;
}
if(f == 0) cout << "No\n";
}
cout << ans1;
return 0;
}
第十二题:蓬莱人形&灭罪「正直者之死」
妹红读完了《蓬莱人形》中有关8名正直者的部分,决定即刻去人里寻找正直者进行灭罪。
结果是,妹红成功找到了N名正直者,并把他们从1~N依次编号,正直者们的身上各自有值为a[i]的正直点数,并就地取材将他们挂在了蓬莱玉枝上形成一条链子。
妹红要在这N名正直者中挑出连续的若干名进行一次灭罪,而在挑选时,只可能出现下面两种情况:
先将选择的若干名正直者的正直点数进行求和,
i)当存在一个选择的区间,使求和的结果刚好等于一个数字M时,可以进行灭罪
ii)当任意一个选择的区间,使求和的结果都不等于一个数字M时,不可以进行灭罪
现在,妹红想请居住在人里的你帮她设计出灭罪的选择方案。
PS:注意选择的区间是连续的,不是任意子区间。
输入格式:
本题仅有一组数据
第一行给出一个正整数N和一个正整数M(1<=N<=1e5,1<=M<=1e7),含义如上述题意
第二行给出N个正整数a[i](1<=i<=N,1<=a[i]<=1e3),含义如上述题意
输出格式:
第一行首先判断妹红能不能进行灭罪
如果不可以,直接输出一个字符串"no way"(引号不输出),结束输出
如果可以,请给出可行的选择方案,格式如下,
每行输出一种选择正直者区间的方案,格式为"l-r"(引号不输出),其中l是选择的左端点编号,r是右端点编号,若方案不唯一,以l递增的顺序输出所有方案。
题目数据保证所有求和的结果均在长整型范围内
输入样例1:
16 15
3 2 1 5 4 6 8 7 16 10 15 11 9 12 14 13
输出样例1:
1-5
4-6
7-8
11-11
样例解释1:
以闭区间[1, 5]为例,内含元素{3, 2, 1, 5, 4},求和3+2+1+5+4正好为15,是一种可行的方案,
此外的[4, 6],[7, 8],[11, 11]区间也是符合求和正好为15的方案之一,此外注意题目要求的递增输出顺序。
输入样例2:
6 100
1 1 4 5 1 4
输出样例2:
no way
样例解释2:
显然,无论怎么选择区间,都不能使求和结果等于100,不存在可行灭罪方案
主要考察前缀和,后面在使用查找,按照题目意思来查找即可。
想要跟详细请看: https://blog.csdn.net/dark__matter_/article/details/137119194
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
using namespace std;
using ll=long long;
const int MAX=1e5+10;
int N;
bool ok; //判断能不能找到合法方案的bool标记
int D[MAX], sum[MAX], M;
void Count(int, int, int);
int main(void){
IOS;
cin>>N>>M;
for(int i=1;i<=N;i++){
cin>>D[i];
if(i==1) sum[i]=D[i];
else sum[i]=sum[i-1]+D[i]; //创建前缀和数组sum保存区间值,sum[n]代表的就是D数组中[1,n]区间值之和
}
Count(0, 1, M); //寻找合法区间函数
if(!ok) cout<<"no way\n";
return 0;
}
void Count(int l, int r, int cmp){ //参数从左至右,依次代表左端点,右端点,需要满足的区间求和值
while(r<=N){ //双指针,快指针l和慢指针r,快指针在后移时要保证始终在慢指针之前,即左端点下标不能够大于右端点下标
while(l<r&&sum[r]-sum[l+1]>=cmp){
l++; //当发现左端点后移一位(当前区间的下界+1)之和,区间值还是大于等于需要满足的求和值时,可以继续移动快指针,直到找到合法的区间
}
int temp=sum[r]-sum[l]; //temp保存l~r区间和
if(temp==cmp){ //如果满足给定值,说明是一个可行方案,更新寻找标记ok,直接输出该次方案即可
ok=true;
cout<<l+1<<'-'<<r<<'\n';
}
r++; //完成这次区间寻找的操作之后慢指针后移一位(当前区间上界+1)
}
}
第十三题:恶魔之妹&秘弹「之后就一个人都没有了吗?」
二小姐芙兰朵露在地下室很无聊,在听说妹红的灭罪后心血来潮,决定去找雾之湖的妖精们玩游戏。
芙兰朵露成功寻找到了N名愿意陪她玩的妖精,依次编号为1~N,游戏是一个简单的捉迷藏,奖品是二小姐最爱的巧克力蛋糕,并且芙兰朵露始终扮演猎人,妖精们始终扮演猎物,猎人通过找到猎物得分,猎物通过逃离到指定的地点得分。
但是对于这个规则,妖精们不满意,因为总是芙兰朵露来充当猎人的角色,于是规定芙兰朵露只可以选择其中一次找到妖精的记录作为最终结算成绩,并且,被抓住的妖精还可以继续进行游戏,得分也不会清除。
为了避免捉迷藏时会晕头转向,她们把捉迷藏的得分记录写在了本子上,共有M行,每行写3个正整数,有且仅可能有以下两种内容:
i)1 id val,操作1,代表妖精方得分,编号为id的妖精得到了值为val的分数
ii)2 l r ,操作2,代表二小姐芙兰朵露得分,她找到了编号在l~r闭区间范围内的妖精,在本次记录中获得的分数为:编号l~r的妖精当前分数总和
(因为雾之湖的妖精们都是智商为⑨的群居生物,她们总是会以一个个集体来行动,被找到的时候也会是一个集体)
初始情况下,所有人得分均为0。
现在,芙兰朵露想请你帮忙计算出,她依据上述规则最多可以获得的得分。
输入格式:
本题仅有一组数据
第一行给出一个正整数N(1<=N<=1e5)和一个正整数M(1<=M<=1e5),含义如上述题意。
接下来M行,每行给出三个正整数(op, id, val或op, l, r)代表得分记录(1<=op<=2, 1<=id<=1e5, 1<=val<=1e5, 1<=l<=r<=1e5),含义如上述题意。
题目数据保证两方一定都有至少一次不为0的有效得分,且芙兰朵露必须选择一次有效得分记录。
输出格式:
输出一个整数,代表芙兰朵露最多可以获得的分数。
题目数据保证所有的的求和结果均在长整型范围内。
输入样例1:
10 2
1 1 5
2 1 10
输出样例1:
5
样例解释1:
初始芙兰朵露和10名妖精均为0分,依据两条得分记录,
第一条表示第1号妖精获得5分,此时妖精方得分为5 0 0 0 0 0 0 0 0 0,
第二条表示芙兰朵露找到了编号1~10的所有妖精,获得5+0+0+0+0+0+0+0+0+0=5分,且必须选择这唯一一条有效记录,获得5分。
输入样例2:
10 4
1 1 4
2 1 10
1 8 9
2 7 9
输出样例2:
9
样例解释2:
依据四条记录,芙兰朵露拥有两条有效分数,分别是4和9,
显然,为了获得最多的得分,芙兰朵露会选择9分的记录。
该题主要考察线段树,在考察二分查找。
想要跟详细请看: https://blog.csdn.net/dark__matter_/article/details/137120212
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
using namespace std;
using ll=long long;
const int MAX=1e5+10;
int n, m;
ll a[MAX], tree[MAX<<2], ans; //这里是把线段树本体存放在一个数组tree中的,由于树形结构特性,每层所耗空间是一般线性数组的4倍,这里就需要开原数组的4倍空间大小
void build(int, int, int); //建立线段树函数
void modify(int, int, int, int, int); //修改单点元素值函数
int quray(int, int, int, int, int); //对区间元素值求和函数
int main(void){
IOS;
cin>>n>>m;
for(int i=1;i<=n;i++)
a[i]=0;
build(1, 1, n); //一开始肯定是基于原有序列进行建树
while(m--){
int f, x, y;
cin>>f>>x>>y;
if(f==1) modify(1, 1, n, x, y); //操作1,修改单源点值
else{
ll temp=quray(1, 1, n, x, y); //操作2,对指定区间求和
ans=max(ans, temp); //寻找单次求和的最大值
}
}
cout<<ans<<'\n';
return 0;
}
void build(int p, int l, int r){ //建立一个下标范围为 l~r 的线段树,根节点从p开始
if(l==r){
tree[p]=a[l]; //递归到叶子节点,直接赋值
return ;
}
int mid=l+r>>1; //向下二分查找左右子树
build(p<<1, l, mid); //建立左子树(上一层结点的下标乘以2)
build((p<<1)+1, mid+1, r); //建立右子树(上一层乘以2后+1)
tree[p]=tree[p<<1]+tree[(p<<1)+1]; //上层结点保存它左右子树结点的和
}
void modify(int p, int l, int r, int id, int val){ //在范围为 l~r 的线段树中修改值
//在第id个位置上增加val
if(l==r){
tree[p]+=val; //二分查找到第x个位置,给当前值+val
return ;
}
int mid=l+r>>1;
if(id<=mid) modify(p<<1, l, mid, id, val);
else modify((p<<1)+1, mid+1, r, id, val); //递归遍历+二分查找左右子树
tree[p]=tree[p<<1]+tree[(p<<1)+1]; //修改结点的值后,同样需要更新它祖先结点的值
}
int quray(int p, int begin, int end, int l, int r){ //计算下标为 l~r 范围的和
if(l<=begin&&end<=r){
return tree[p]; //当递归遍历的区间真包含了待查找的区间,直接返回当前结点的值
}
int mid=begin+end>>1; //递归+二分左右子树
if(r<=mid) return quray(p<<1, begin, mid, l, r); //如果待查找的右区间都比当前遍历区间中点要小
//(即待查找的区间完全在左子树部分),递归左子树
else if(l>mid) return quray((p<<1)+1, mid+1, end, l, r); //同上理解,遍历右子树
return quray(p<<1, begin, mid, l, mid)+quray((p<<1)+1, mid+1, end, mid+1, r);
//如果左右子树两边都与待查找区间存在交集情况,那么两边都需要递归
}
第十四题:副会长的CSGO2作业寄了
“CSGO2作业买了吗?”
“没有买。”
“还不快买?”
“行,买,在买一次,最后一次买了...”
确实如此,CSGO2第一届major来了,CSGO2的粉丝的节目也来了,估计会有很多赌狗和我一样买了CSGO2的作业,天天熬夜看比赛,希望自己的作业对五个及以上。
倪会长作为G2战队的粉丝,他一定想尽可能多的完整看比赛了,当然,他还是会看看其他游戏的比赛的,比如:英雄联盟…扯远了。
假设你已经知道了major所有赛场的时间表,你能帮倪会长数一数他一天内最多看几场比赛吗?(看完整场比赛),并且给倪会长说一说你数出的赛程,让倪会长好设置闹钟去看比赛。
输入格式:
每个输入包含一个测试用例,每个测试用例先给出一个n(1<=n<=1e4),代表major今天的赛程,下面n行给出两个时间点,分别表示比赛的开始时间和比赛的结束时间(结束时间可以和开始时间一样哦),时间是24小时制。
输出格式:
对于每个测试实例,输出倪会长最多能完整看比赛的个数max,在下一行开始输出比赛的时间(时间按照升序输出,即第二个比赛的开始时间要大于等于第一个比赛的结束时间,每个时间段占一行)。如果max有多个,则下面比赛的时间输出结束时间最小max的即可。输出时若是个位数的时间,在输出时加前导0。
输入样例:
4
03:29 03:45
02:45 02:56
05:14 06:38
04:35 09:59
输出样例:
3
02:45 02:56
03:29 03:45
05:14 06:38
该题主要考察贪心算法,需要使用结构体排序。还有按照题目意思去模拟。
第一张解法:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct pai {
int h1, m1, h2, m2;
int cnt = 1;
}a[10001];
bool cmp(pai x, pai y) {
if(x.h2 != y.h2) return x.h2 < y.h2;
return x.m2 < y.m2;
}
int main() {
ios::sync_with_stdio(0);
cout.tie(0);
cin.tie(0);
int n;
cin >> n;
char c;
for(int i = 0; i < n; i++)
cin >> a[i].h1 >> c >> a[i].m1 >> a[i].h2 >> c >> a[i].m2;
if(n == 1) {
printf("1\n%02d:%02d %02d:%02d\n",a[0].h1,a[0].m1,a[0].h2,a[0].m2);
return 0;
}
sort(a, a + n, cmp);
int maxx = 0;
for(int i = 0; i < n; i++) {
int h2 = a[i].h2, m2 = a[i].m2;
for(int j = i + 1; j < n; j++) {
if(a[j].h1 == h2) {
if(a[j].m1 >= m2) {
a[i].cnt++;
h2 = a[j].h2; m2 = a[j].m2;
}
}
else {
if(a[j].h1 >= h2) {
a[i].cnt++;
h2 = a[j].h2; m2 = a[j].m2;
}
}
}
maxx = max(a[i].cnt, maxx);
}
cout << maxx << endl;
int k = 0;
for(int i = 0; i < n; i++) {
int h2 = a[i].h2, m2 = a[i].m2;
for(int j = i + 1; j < n; j++) {
if(a[i].cnt == maxx) {
if(k == 0) printf("%02d:%02d %02d:%02d\n",a[i].h1,a[i].m1,a[i].h2,a[i].m2), k++;
if(a[j].h1 == h2) {
if(a[j].m1 >= m2) {
h2 = a[j].h2, m2 = a[j].m2;
printf("%02d:%02d %02d:%02d\n",a[j].h1,a[j].m1,a[j].h2,a[j].m2);
}
}
else {
if(a[j].h1 >= h2) {
h2 = a[j].h2, m2 = a[j].m2;
printf("%02d:%02d %02d:%02d\n",a[j].h1,a[j].m1,a[j].h2,a[j].m2);
}
}
}
}
if(k != 0) break;
}
return 0;
}
第二种解法:
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
using namespace std;
using ll=long long;
const int MAX=1e4+10;
struct xx{
int h1, m1, h2, m2;
ll cmp1, cmp2;
bool operator < (const xx &t) const {
// if(this->cmp1!=t.cmp1) return this->cmp1 < t.cmp1;
// return this->cmp2 < t.cmp2;
return this->cmp2 < t.cmp2;
}
}tt[MAX];
ll ans, num;
vector<int> v;
int main(void){
// IOS;
int n; char op;
cin>>n;
for(int i=0;i<n;i++){
cin>>tt[i].h1>>op>>tt[i].m1>>tt[i].h2>>op>>tt[i].m2;
tt[i].cmp1=tt[i].h1*60+tt[i].m1;
tt[i].cmp2=tt[i].h2*60+tt[i].m2;
}
sort(tt, tt+n);
ll now=0;
for(int i=0;i<n;i++){
// cout<<tt[i].h1<<' '<<tt[i].m1<<' '<<tt[i].h2<<' '<<tt[i].m2<<'\n';
if(now<=tt[i].cmp1){
num++;
v.push_back(i);
now=tt[i].cmp2;
}
}
cout<<num<<'\n';
for(auto it:v){
printf("%02d:%02d %02d:%02d\n", tt[it].h1, tt[it].m1, tt[it].h2, tt[it].m2);
}
return 0;
}
第十五题:贪心挑数
已知n个整数,和两个整数m和k(m < n, k = 0, 1), 从n个整数中任意选择m个整数相加和相乘, 并且根据k进行判断它的乘积是偶数还是奇数(0代表偶数, 1代表奇数),得到的和将进行判断是否为素数,得到的乘积将为判断是否为满足k的条件。
例如,n = 2, m = 2, k = 0, 2个整数分别为1, 2时, 可得到的组合为:
和:1 + 2 = 3
积:1 * 2 = 2
结果:3为素数, 2为偶数 满足条件
输入格式:
第一行三个空格隔开的整数n, m , k ( 1 ≤ n ≤ 10, m < n, k = 0, 1)。
第二行n个整数,分别为 a1, a2, ...an( 1 ≤ ai ≤ 100)。
输出格式:
现在小倪不知道m个相加为素数和相乘为(偶数或奇数)的个数共有多少种,请你帮帮他解决这一问题。
输入样例1:
10 1 1
1 3 5 7 9 2 4 6 8 10
输出样例1:
3
输入样例2:
10 1 0
1 3 5 7 9 2 4 6 8 10
输出样例2:
1
样例解释
样例1:10个数选其中为乘积为奇数,和为质数有3个,分别是3, 5, 7, 9。
样例2:10个数选其中为乘积为偶数,和为质数有1个,分别是2。
该题主要考察dfs,按照题目大意搜索即可。
#include<bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
#define IOS std::ios::sync_with_stdio(false), std::cin.tie(nullptr), std::cout.tie(nullptr)
#define all(v) (v).begin(),(v).end()
void debug(std::vector <int> &a, int n){for (int i = 1; i <= n; i ++){std::cout << a[i] << " \n"[i == n];}}
void YES(){std::cout << "YES\n";}
void NO(){std::cout << "NO\n";}
void Yes(){std::cout << "Yes\n";}
void No(){std::cout << "No\n";}
void yes(){std::cout << "yes\n";}
void no(){std::cout << "no\n";}
const int N = 2e5 + 10;
constexpr i64 mod1 = 998244353, mod2 = 1e9 + 7;
i64 ans = 0;
int n, m, k;
int a[20];
bool isprime(int x){
if (x <= 1) return false;
if (x == 2 or x == 3) return true;
for (int i = 2; i <= x / i; i ++){
if (x % i == 0){
return false;
}
}
return true;
}
bool check(int sum1, i64 sum2){
if (!isprime(sum1)) return false;
if (k == 0){
if (sum2 % 2 != 0){
return false;
}
}else {
if (sum2 % 2 == 0){
return false;
}
}
return true;
}
void dfs(int cnt, int sum1, i64 sum2, int st){
if (cnt == m){
if (check(sum1, sum2)){
// std::cout << sum1 << " " << sum2 << "\n";
ans ++;
}
return ;
}
for (int i = st; i < n; i ++){
dfs(cnt + 1, sum1 + a[i], sum2 * a[i], i + 1);
}
return ;
}
int main()
{
IOS;
std::cin >> n >> m >> k;
for (int i = 0; i < n; i ++){
std::cin >> a[i];
}
dfs(0, 0, 1, 0);
std::cout << ans << "\n";
return 0;
}
总结:
本次团体赛主要考察的算法有模拟、数学、字符串、二分查找,前缀和、线段树、搜索、贪心、结构体排序、递归。
希望题解能帮到大家。期待下一年大家的表现。