团体程序设计天梯赛-L1部分全题解

前言

​ 这篇题解每一篇都是我亲手写的,为了严谨写的尽量标准一些,也参考了大量的博客和其他题解,一共收录了\(180\) 道题,均来自官方训练系统,每份代码也都是我亲手写的,然后提交到OJ上无误才贴上去的,除非官方增强数据,否则不需要担心代码的对错与否。

​ 一些模拟题的限制是\(400ms\) ,根据时间复杂度换算,最多支持\(10^7\) 的计算,跟\(1s\) 差不了太多。

​ L1部分大部分是很简单的模拟题,也有一些需要思考枚举范围或模拟过程的,也许你编程功底很好,觉得这些题目一眼出思路不需要写,但赛时一些恶心的模拟题能把你卡到一小时动不了,锻炼模拟题才是真正的编程入门,这章很多模拟题都有设一些经常会卡人的点,所以不要觉得写L1的题浪费时间或者太简单而不去练,不会做的题做不出来没什么,会做的题有思路但就敲不对才是最捉急的。

以湛科两次比赛成绩和相同层次学校的统计,大部分人的模拟题都没有拿满(每题总是差\(1,2\) 分),这也许在评奖或者团队奖贡献中起关键作用→如果你的L1分数不够,L2L3的分数无效,如果团队L1分数之和不够,团体L2L3的分数无效(也就是说,若你的L1分数拖了团队后腿,那么整个队伍的L2分数均无效)

​ L1部分你至少需要学会:C++基础语法,STL,基础数据结构,算法竞赛输入输出技巧。

​ 写于\(2023.4.21\) ,完工于\(2023.7.23\) –羽肿

L1-001 Hello World

​ 这种打印题一般放第一题,不要用其他语言写,直接把语言调成python ,然后用print() 输出

1
print("Hello World!")

L1-002 打印沙漏

​ 很简单的模拟题,但也很考验选手的模拟思考能力,由于沙漏上下对称,发现上面是一个呈现等差数量的形状,也就是\(1,3,5\) 个星星,那上半部分的星星总和就是\((层数)^2\) ,沙漏的星星总和是\(2*(层数)^2\) ,由于只能少不能多,所以应该满足\(2*(层数)^2-1 \le k\) (中间那个单独的一颗星星被重复计算了要减去),然后解出来得到\(n=\sqrt{(k+1)/2}\) ,得到层数后直接逆序和正序模拟输出等差数列般的星星即可

​ 刚刚说了星星的总和是\(2n^2-1\) ,则剩余的星星是\(k-(2n^2-1)\)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <math.h>
using namespace std;
const int N=1e5;
typedef long long ll;
typedef unsigned long long ull;
#define lowbit(x) x&-x
char c;
int k,n;
int main(){
    cin>>k>>c;
    n=sqrt((k+1)/2);
    for(int i=n;i>=1;i--){ //逆序
    	for(int j=1;j<=n-i;j++)cout<<" ";
    	for(int j=1;j<=2*i-1;j++)cout<<c;
    	cout<<endl;
	}
	for(int i=2;i<=n;i++){ //正序
    	for(int j=1;j<=n-i;j++)cout<<" ";
    	for(int j=1;j<=2*i-1;j++)cout<<c;
    	cout<<endl;
	}
	int sum=2*(n*n)-1;
	cout<<k-sum<<endl;
}

L1-003 个位数统计

​ 题目大概意思是,给一个十进制数字,求每个数字出现的次数

​ 设\(a[i]\) 为数字\(i\) 的出现次数,用字符串\(s\) 读入数字,然后遍历\(s[i]\)每一位数字,处理\(a[s[i]]++\) 即可

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <math.h>
using namespace std;
const int N=1e5;
typedef long long ll;
typedef unsigned long long ull;
#define lowbit(x) x&-x
string s;
int a[10];//最多就10个数字
int main(){
    cin>>s;
    for(int i=0;i<s.size();i++){
    	a[s[i]-'0']++;//s[i]-'0'是处理成数字
	}
	for(int i=0;i<10;i++){
		if(a[i]>0){
			cout<<i<<":"<<a[i]<<endl;
		}
	}
}

L1-004 计算摄氏温度

​ 很简单的模拟题,像这种没什么逻辑的题目就不要用cpp了,直接用python。

1
2
3
c=float(input())
ans=(5*(c-32))/9
print("Celsius = %d"%(ans))

L1-005 考试座位号

​ 题目大意是,每个人都有个准考证 A座位号 B座位号,现在就只给你\(B\) 座位号,求准考证号和\(A\) 座位号,保存一下就可以了,然后遍历查询。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
using namespace std;
const int N=1e3+7;
struct node{
	string no,a,b;
}t[N]; 

int main(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		string no,a,b;
		cin>>no>>a>>b;
		t[i]={no,a,b};//cpp11新写法,更方便
	}
	int tt;
	cin>>tt;
	while(tt--){
		string a;
		cin>>a;
		for(int i=1;i<=n;i++){
			if(t[i].a==a){
				cout<<t[i].no<<" "<<t[i].b<<"\n";
				break;
			}
		}
	}
}

L1-006 连续因子

​ 首先数字\(n<2^{31}≠2^{31}\) ,大概就是\(10^9\) 左右的范围,恰好是整形的极限。

​ 一个数的因子在\(2\sim \sqrt{n}\) (成对出现),对于一个值\(i\) ,只需要枚举以\(i\) 开头的最长连续因子,如果以\(i\) 开头的连续因子是否存在,即\(i*(i+1)*..*(i+k)*j\) ,然后需要判断这个连续因子序列是否是正确的,只需看这个序列是否被可以被整除,例如\(2,3,4,9\) 这个序列,虽然\(9\) 并不连续,但\(216\%(2*3*4)=0\) ,另一半是什么不需要管,然后就可以得到以\(i\) 开头的最长连续因子,然后对每一个开头都这么操作,最后取一次最长的就可以了。

​ 对于第二问,最小连续因子是所有「最长连续因子」中首元素最小的那个(题目有些歧义),那只需要用给一个起始指针\(start\) 和长度指针\(len\) 维护下信息就好了,然后只有大于了长度才更新就好了(不加等于),这样记录的就是最早(也就是首元素最小的)的序列了。

​ 数据规模很大,需要考虑时间复杂度是否合法,由于枚举是\(O(\sqrt n)\) ,每次操作最多\(O(\sqrt n)\) ,输出长度是一个很小的常数可以忽略不计,总复杂度大概就是\(O(n+k)\) 的样子,均摊下来能过,事实上根据题目范围和阶乘大小,\(2^{31}\) 次方的连续因子不会超过\(12\) 个,也就是实际上大概就是\(O(12\sqrt n)\) 的复杂度罢了。

​ 注意一种特殊情况:素数是没有任何除\(1*本身\)因子的,所以最长连续因子就是本身,

​ 这里要额外注意一下:取值范围应该是\([2,\sqrt n]\) 但右端点应该是向上取整,否则会卡一个样例,原理是:假设\(n\) 并不是一个平方数,向上取整为\(k^+\) ,向下取整为\(k^{-}\) ,如果只限制在\(k^{-}\) 的话,会使得原本\(n=k^+*k^-\) 的数字出错,至少\(6\) 就是,\(\sqrt 6=2\)\(2*(2+1)=6\) ,所以加上一个\(1\) 就好了。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>
#include <math.h>
using namespace std;
typedef int ll;//忽略。
ll n;
ll pre;
ll start,len;

bool isprime(int n){//判断素数
	for(int i=2;i<=sqrt(n);i++){
		if(n%i==0)return false;
	}
	return true;
}

int main(){
	cin>>n;
	if(isprime(n)){
		cout<<1<<"\n"<<n;
		return 0;
	}
	for(ll i=2;i<=sqrt(n)+1;i++){
		pre=1;
		for(ll j=i;j<=sqrt(n)+1;j++){
			pre*=j;
			if(n%pre==0){
				if(j-i+1>len){
					len=j-i+1;
					start=i;
				}
			}
			else break; //如果断了就结束 
		}
	} 
	cout<<len<<"\n";
	for(int i=0;i<len;i++){
		if(i!=0)cout<<"*";
		cout<<start+i;
	}
	return 0;
}

L1-007 念数字

​ 很简单的模拟题,string s[10] 代表数字\(i\) 的拼音(用字符串存储),然后特判是否是负,是的话就输出一个fu 就行了,\(0\) 不用特判。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#include <iostream>
#include <math.h>
using namespace std;
string s[10];
string a;

int main(){
	s[0]="ling",s[1]="yi",s[2]="er",s[3]="san",s[4]="si";
	s[5]="wu",s[6]="liu",s[7]="qi",s[8]="ba",s[9]="jiu"; 
	cin>>a;
	for(int i=0;i<a.size();i++){
		if(a[i]=='-')cout<<"fu";
		else cout<<s[a[i]-'0'];
		if(i!=a.size()-1)cout<<" ";
	}
	return 0;
}

L1-008 求整数段和

​ 很简单的模拟题,只需要枚举\(a,b\) 上所有数字,依次输出并求和即可,但要注意一下输出每隔5个就要换行以及每个单词占\(5\) 个长度(可以用iomanip的\(setw\) 来控制),以及最后一行不够\(5\) 个的时候也要额外输出

​ 比较考察格式化输入输出吧,也没什么难度。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <math.h>
#include <iomanip>
using namespace std;
int a,b; 
int cnt;
int sum;
int main(){
	cin>>a>>b;
	while(a<=b){
		cout<<setw(5)<<a;
		cnt++;
		sum+=a;
		if(cnt%5==0)cout<<"\n";
		a++;
	}
	if(cnt%5!=0)cout<<"\n";
	cout<<"Sum = "<<sum;
}

L1-009 N个数求和

​ 这道题稍微有点难度,但已有基础的应该就是一个简单的基于数论的模拟

​ 这题涉及到数论,建议先学习后再做。

​ 根据小学知识,多个不同分母的分数相加先通分,通分的本质是将寻找这些分母的最小公倍数,又据数论知识:\(gcd(a,b)*lcm(a,b)=a*b\) ,又\(gcd(a,b,c)=gcd(gcd(a,b),c)\) (多个数字的\(gcd\) 等价于各自\(gcd\) 后再求一次\(gcd\) ),这里涉及求多个数字的最小公倍数,则\(lcm(a,b,c)=lcm(lcm(a,b),c)\) ,将公式代入则\(lcm(a,b,c)=lcm(a,b)*c/gcd(lcm(a,b),c)\) ,所以只需要一个\(lcm\) 在遍历过程中就可以求得最小公倍数。

​ 然后我们得到了\(lcm\), 由于分母乘以倍数到达了\(lcm\) ,分子也要乘上去,我们得到通分后的分子后,加起来就得到了\(所有分子之和/lcm\) ,此时不一定是最简分数,又据数论知识,如果一个分数是最简分数,则一定有\(gcd(分子,分母)=1\) (无其他公约数),否则如果\(gcd()=k\) ,说明\(\frac{a}{b}=\frac{k*a'}{k*b'}\) ,完全能约掉这个\(k\) ,所以对于结果我们求一次\(gcd\) ,然后上下两边都除这个\(gcd\) ,直至\(gcd(a,b)=1\)

​ 样例点的坑很多,经过无数次试错后,如下:

测验点3:这些分母的公倍数可能非常大,例如\(90*91*..*100>10^{9}\) ,已经超出了\(int\) 范围,需要用长整型表示。

测验点4:如果得到的分子是\(0\) ,就直接输出\(0\) 即可,否则会输出\(0/2\) 之类的。

测验点5:处理整数部分不能简单的用\(分子>分母\) 来判断有没有整数,\(-6/-3\) ,虽然分子比分母小,但仍然可以约成整数\(-2\)

测验点6:例如\(-50/1000\) ,由于公约数会得到一个负数,导致化简的时候得到\(1/-20\) ,只需要将公约数修正成整数即可。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
#include <math.h>
#include <iomanip>
typedef long long ll;
using namespace std;
const ll N=107; 
ll a[N];//分子 
ll b[N];//分母 
ll ans;
ll n;
ll lcm=1;
ll gcd(ll a,ll b){
	return b?gcd(b,a%b):a;
}
int main(){
	cin>>n;
	for(ll i=1;i<=n;i++){
		scanf("%lld/%lld",&a[i],&b[i]);
		lcm=lcm/gcd(b[i],lcm)*b[i];
	}
	for(ll i=1;i<=n;i++){
		ll d=lcm/b[i];//第i位要扩到公倍数需要多少倍
		a[i]*=d;//分子也要乘上 
		ans+=a[i];
	}
	if(ans==0){
		cout<<"0";
		return 0;
	}
	if(ans%lcm!=ans){ //处理整数部分 可以用ans%lcm 是否还是ans来判断有无整数部分
		cout<<ans/lcm;
		if(ans%lcm==0){
			return 0;
		}
		cout<<" ";//注意输出格式。
		ans=ans%lcm;
	}
	while(1){
		ll d=gcd(ans,lcm);
		if(d<0)d*=-1; //测验点6
		if(d==1)break;//已经是最简分数
		ans/=d;
		lcm/=d;
	}
	cout<<ans<<"/"<<lcm;
	return 0;
}

​ 这题主要是考察数论知识,然后也很考验模拟的功底,有很多测验点的坑巨多,需要逐个分类讨论。

L1-010 比较大小

​ 比较简单的模拟题,排序后输出就行了(当然也可以用分支结构,但非常浪费时间)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#include <iostream>
#include <algorithm>
using namespace std;
int a[3];


int main(){
	cin>>a[0]>>a[1]>>a[2];
	sort(a,a+3);
	cout<<a[0]<<"->"<<a[1]<<"->"<<a[2];
    return 0;
}

L1-011 A-B

​ 比较简单的模拟题,主要考的是字符串哈希,直接模拟即可,在\(b\) 中有的不输出就行

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <set>
using namespace std;
string s;
string t;
set<char> tmp;

int main(){
	getline(cin,s);//注意按行输入
	getline(cin,t);
	for(int i=0;i<t.size();i++){
		char c=t[i];
		tmp.insert(c);
	}
	for(int i=0;i<s.size();i++){
		if(!tmp.count(s[i]))cout<<s[i];
	}
	return 0;
}

L1-012 计算指数

​ 比较简单的模拟题,\(n\) 不超过\(10\) ,结果最大才\(1024\) ,直接用python模拟。

1
2
c=int(input())
print("2^%d = %d"%(c,2**c))

L1-013 计算阶乘和

​ 比较简单的模拟题,\(10!\) 大概\(300w\) 这样,用\(int\)够了。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#include <iostream>
using namespace std;
int main(){
	int n;
	cin>>n;
	int pre=1;
	int ans=1;
	for(int i=2;i<=n;i++){
		pre*=i;
		ans+=pre;
	}
	cout<<ans;
    return 0;
}

L1-014 简单题

​ 同\(L1-001\)

L1-015 跟奥巴马一起画方块

​ 很简单的模拟题,两层循环就可以了,注意四舍五入函数的使用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#include <iostream>
#include <math.h>
using namespace std;
int main(){
	double n;
	cin>>n;
	int k=round(n/2);//四舍五入前提是n/2得是小数 所以n得是小数类型
	string c;
	cin>>c;
	for(int i=1;i<=k;i++){
		for(int j=1;j<=n;j++){
			cout<<c;
		}
		if(i!=k)cout<<"\n";
	}
}

L1-016 查验身份证

​ 很简单的模拟题,字符串哈希一下就可以了(用char数组也可以,还更快了)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <iostream>
#include <map>
#include <math.h>
using namespace std;
string s;
int p[17]={7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2}; 
map<int,char> tmp;

void pre(){
	tmp[0]='1';
	tmp[1]='0';
	tmp[2]='X';
	tmp[3]='9';
	tmp[4]='8';
	tmp[5]='7';
	tmp[6]='6';
	tmp[7]='5';
	tmp[8]='4';
	tmp[9]='3';
	tmp[10]='2';
}

int check(const string& s){
	int sum=0;
	for(int i=0;i<s.size()-1;i++){
		int end=s[i]-'0';
		sum+=end*p[i];
	}
	sum%=11;
	char t=tmp.find(sum)->second;
	return t==s[s.size()-1];
}

int main(){
	int n;
	cin>>n;
	pre();
	int flag=1;
	for(int i=1;i<=n;i++){
		cin>>s;
		if(!check(s)){
			cout<<s<<endl;
			flag=0;
		}
	}
	if(flag)cout<<"All passed";
	return 0;
} 

L1-017 到底有多二

​ 一道很简单但比较有意思的模拟题,用字符串接受然后对每个字符统计\(2\) 的个数,然后再按题目需求就可以了,但这里要处理好,由于精度丢失,分子乘\(1.5\) 等价于分子乘\(3\) ,分母乘\(2\) ,然后如何判断是否是偶数呢?肯定不能用数字接受了,因为题目是最长\(50\) 位,\(10^{50}>10^{19}\) ,已经没办法用数字类型接受了,其实转转脑筋就可以发现,偶数不就是个位数是\(0,2,4,6,8\) 的吗?这样就不需要用\(n\%2\) 了,只需要判断个位即可。

​ 要注意负数的时候字符串长度就不等于数字长度了,因为多了个负号。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <map>
#include <math.h>
using namespace std;


int main(){
	string s;
	cin>>s;
	double n=s.size();
	double nn=n;
	double two=0;
	int neg=0;
	for(int i=0;i<s.size();i++){
		if(s[i]=='-'){
			neg=1;
			continue;
		}
		int num=s[i]-'0';
		if(num==2)two++;
	}
	if(neg)nn--;//如果是负号说明要减去一个长度 
	double ans=100*two/nn;
	if((s[n-1]-'0')%2==0){
		ans*=2.0;
	}
	if(neg){
		ans*=1.5;
	}	
	printf("%.2lf\%%",ans);
    return 0;
}

L1-018 大笨钟

​ 很简单的模拟题,理解题意后输出就可以了,注意%02d 这个神奇用法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <map>
#include <math.h>
using namespace std;
int main(){
	int h,m;
	scanf("%d:%d",&h,&m);
	if(h<12){
		printf("Only %02d:%02d.  Too early to Dang.",h,m);
		return 0;
	} 
	if(h==12&&m==0){
		printf("Only %02d:%02d.  Too early to Dang.",h,m);
		return 0;
	}
	h-=12;
	if(m>0)h++;
	while(h--){
		cout<<"Dang";
	}
    return 0;
}

L1-019 谁先倒

​ 很简单的模拟题,就是有点麻烦。用\(ha,hb\) 记录\(a,b\) 各自喝了多少,一旦有人超过了酒量就马上中止,然后打印。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <map>
#include <math.h>
using namespace std;
int ha,hb;
int a,b;
int tt;

int main(){
	cin>>a>>b>>tt;
	while(tt--){
		int sa,ta;
		int sb,tb;
		cin>>sa>>ta>>sb>>tb;
		int t=(sa+sb);
		if(ta==t&&tb!=t){ //如果A被罚酒 
			ha++;
		}
		else if(tb==t&&ta!=t){ //如果B被罚酒 
			hb++;
		}
		if(hb>b||ha>a)break;//倒了就中止
	}
	if(ha>a){
		cout<<"A"<<endl;
		cout<<hb;
	}
	else{
		cout<<"B"<<endl;
		cout<<ha;	
	}
    return 0;
}

L1-020 帅到没朋友

​ 将数值映射到下标,\(a[i]\) 代表\(i\) 是否是帅到没朋友的(\(0\) 代表没朋友),很显然没有朋友的就是给出的\(n\) 个朋友圈都没加入过他,以及只有\(1\) 个人的朋友圈的那个人也可能是没朋友。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <map>
#include <math.h>
using namespace std;
const int N=1e5+7;
int a[N];
int vis[N];
int main(){
	int n;
	cin>>n;
	while(n--){
		int k;
		cin>>k;
		int flag=1;
		if(k==1)flag=0;
		while(k--){
			int val;
			cin>>val;
			a[val]=a[val]==1?1:flag; //防止后面单独朋友圈被人覆盖了 
		}
	} 
	int m;
	int ok=0;
	cin>>m;
	for(int i=1;i<=m;i++){
		int val;
		cin>>val;
		if(!a[val]&&!vis[val]){
			if(ok)cout<<" ";//这个控制输入输出很巧妙。
			printf("%05d",val);
			vis[val]=1;//用vis数组来标记是否被列出来过 不能重复列出来。
			ok=1;
		}
		
	}
	if(!ok)cout<<"No one is handsome"; 
}

L1-021 重要的话说三遍

​ 还是那句话,能用python的别用其他语言

1
2
for i in range(0,3):
    print("I'm gonna WIN!")

L1-022 奇偶分家

​ 很简单的模拟题,分别统计就可以了,不过这里额外介绍一个技巧,若一个数是奇数,则\((i\&1)==1\) (二进制原理),用位运算会快一点点。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <map>
#include <math.h>
using namespace std;

int main(){
	int n,ji=0,ou=0;
	cin>>n;
	while(n--){
		int k;
		cin>>k;
		if(k&1){
			ji++;
		} 
		else ou++;
	}
	cout<<ji<<" "<<ou;
	return 0;
}

L1-023 输出GPLT

​ 很简单的模拟题,统计个数,然后依次输入即可,有的就输入,没有就略过。

​ 由于不区分大小写,不妨将字符串先转为小写,省的判断这么多。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <algorithm>
#include <math.h>
using namespace std;
string s;
int g,p,l,t;
int main(){
	cin>>s;
	transform(s.begin(),s.end(),s.begin(),::tolower);
	for(int i=0;i<s.size();i++){
		if(s[i]=='g')g++;
		else if(s[i]=='p')p++;
		else if(s[i]=='l')l++;
		else if(s[i]=='t')t++;
	}	
	while(1){
		if(!(g||p||l||t))break;//一个都没有了就中止
		if(g){
			cout<<"G";g--;
		}
		if(p){
			cout<<"P";p--;
		}
		if(l){
			cout<<"L";l--;
		}
		if(t){
			cout<<"T";t--;
		}
		
	} 
	return 0;
}

L1-024 后天

​ 很简单的模拟题,注意用取模来模拟就行了

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#include <iostream>
#include <algorithm>
#include <math.h>
using namespace std;

int main(){
	int n;
	cin>>n;
	n=(n+2);
	if(n>=8)n-=7;
	cout<<n;
	return 0;
}

L1-025 正整数A+B

​ 比较简单的模拟题,但要注意输入输出和判断,然后就是有个测试点会有\(12\ 12\ 1.2\) 这种样例,这时候意味着\(a=12,b="12\ 1.2"\) ,所以是不符合的,需要用getline 吸取整行。

​ 比较考字符串模拟和互转调用吧,还好。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <algorithm>
#include <math.h>
using namespace std;
string a,b;
int aa,bb;//合法性 

int check(string s){
	for(int i=0;i<s.size();i++){
		if(s[i]<'0'||s[i]>'9')return true;
	}
	//非整数数字判断
	int n=atoi(s.data());
	if(n<1||n>1000)return true;
	return false;
}

int main(){
	cin>>a;
	getchar();//要吸取一下
	getline(cin,b);
	aa=check(a);bb=check(b);
	if(aa)cout<<"?";
	else cout<<a;
	cout<<" + ";
	if(bb)cout<<"?";
	else cout<<b;
	cout<<" = ";
	if(aa||bb)cout<<"?";
	else{
		int a1=atoi(a.data());
		int b1=atoi(b.data());
		cout<<a1+b1;
	}
}

L1-026 I Love GPLT

​ 每个字符(包括空格)后面都加个换行符就可以了。

1
print("I\n \nL\no\nv\ne\n \nG\nP\nL\nT")

L1-027 出租

​ 比较简单的模拟题,就是映射的问题,先从小到大把出现过的数字排序一下,得到第一个答案,第二个答案直接双重循环for就可以了,这类模拟题不追求效率,只要想到了一个可以做的方案就马上敲,没必要想一些花招或者什么优化,唯一的贡献就是浪费了你的时间。赛时没有时间供你对一道靠手速就能解决的问题思来想去。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>
#include <algorithm>
#include <math.h>
#include <vector>
using namespace std;
const int N=12;
string s;
vector<char> arr;
int vis[N];
vector<char> ans;
int main(){
	cin>>s;
	for(int i=0;i<s.size();i++){
		if(vis[s[i]-'0'])continue;
		arr.push_back(s[i]);
		vis[s[i]-'0']=1;
	}
	sort(arr.begin(),arr.end(),greater<char>());//降序
	cout<<"int[] arr = new int[]{";
	int ok=0;
	for(auto v:arr){
		if(ok)cout<<",";
		cout<<v;
		ok=1;
	}
	cout<<"};\n";
	cout<<"int[] index = new int[]{";
	ok=0;
	for(int i=0;i<s.size();i++){
		for(int j=0;j<arr.size();j++){
			if(s[i]==arr[j]){
				if(ok)cout<<",";
				cout<<j;
				ok=1;
				break;
			}
		}
	}
	cout<<"};";
}

L1-028 判断素数

​ 数论的入门板子题,不懂的话学完再来(虽然这个不学数论一样能写得出来)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <algorithm>
#include <math.h>
#include <vector>
using namespace std;

int main(){
	int tt;
	cin>>tt;
	while(tt--){
		int n;
		cin>>n;
		if(n==1){ //注意1不是数论
			cout<<"No\n";
			continue;
		}
		int flag=1;
		for(int i=2;i<=n/i;i++){
			if(n%i==0){
				flag=0;
				break;
			}
		}
		if(flag)cout<<"Yes";
		else cout<<"No";
		cout<<endl;
	}
}

L1-029 是不是太胖了

​ 很简单的模拟题,注意保留小数就是了

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#include <iostream>
#include <algorithm>
#include <math.h>
#include <vector>
using namespace std;

int main(){
	double n;
	cin>>n;
	n=(n-100)*0.9;
	printf("%.1f",2*n);
}

L1-030 一帮一

​ 很简单的模拟题,每次逆序寻找一个没带过并且是异性的就可以了,还是那句话:模拟题除非数据很大否则不需要考虑时间复杂度

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
using namespace std;
const int N=57;
int vis[N];
struct node{
	int sex;
	string name;
}s[N];
int main(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		int sex;
		string name;
		cin>>sex>>name;
		s[i].sex=sex;
		s[i].name=name;
	}
	for(int i=1;i<=n;i++){
		if(vis[i])break;//如果这个人是被带的 那么后面都是被带的 被带的没资格带别人
		for(int j=n;j>=1;j--){
			if(!vis[j]&&s[j].sex!=s[i].sex){ //如果这人没被带过并且是异性 
				cout<<s[i].name<<" "<<s[j].name<<endl;
				vis[j]=1;
				break;
			}
		}
	}
    return 0;
}

L1-031 到底是不是太胖了

​ 模拟即可,这里隐含一个消息:不完美的时候,真实体重大于完美体重就是太胖了,反之一样。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
#include <algorithm>
#include <math.h>
#include <vector>
using namespace std;
double real;
double stand; 
int main(){
	int tt;
	cin>>tt;
	while(tt--){
		int h;
		cin>>h;
		stand=(h-100)*1.8;//*2*0.9
		cin>>real;//真实
		double d=abs(real-stand);
		if(d<stand*0.1){
			cout<<"You are wan mei!";
		}
		else{
			if(real<stand){
				cout<<"You are tai shou le!";
			}
			else{
				cout<<"You are tai pang le!";
			}
		}
		cout<<"\n";
	}
}

L1-032 Left-pad

​ 一道比较有意思的模拟题,当控制长度大于字符串长度时,那少的部分就用字符填充,否则,就只输出最后一个控制长度长度的字符。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <algorithm>
#include <math.h>
#include <vector>
using namespace std;
string s;
char c;
int n;
int main(){
	cin>>n>>c;
	getchar();
	getline(cin,s);
	int len=s.size();
	if(len<=n){ 
		for(int i=1;i<=n-len;i++)cout<<c;
		cout<<s;
	}
	else{
		for(int i=len-n;i<=len-1;i++){
			cout<<s[i];
		}
	}
	return 0;
}

L1-033 出生年

​ 比较简单的模拟题,就是处理前置\(0\) 比较麻烦,然后写一下检查函数就很简单了。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
#include <algorithm>
#include <math.h>
#include <vector>
using namespace std;
const int N=12;
int a[N];
int y,k;

int check(string s){ //检查字符串s是否有k个不同的数字
	int ans=0;
	for(int i=0;i<=9;i++)a[i]=0;//记得重置。
	for(int i=0;i<s.size();i++){
		if(!a[s[i]-'0']){ //如果这个数字被用过了就不累加到答案
			ans++; //否则就是有新数字了
			a[s[i]-'0']=1;//标记
		}
	}
	return ans==k;
}
int main(){
	cin>>y>>k;
	for(int i=y;;i++){//循环
		string n=to_string(i);
		if(i<1000){ //不够的话补一下0
			int nn=n.size();
			string pre;
			for(int j=1;j<=4-nn;j++){
				pre+='0';
			}
			n=pre+n;
		}
		if(check(n)){
			cout<<i-y<<" "<<n;
			return 0;
		}
	}
}

L1-034 点赞

​ 还是经典的统计类模拟题,(由此可以发现,统计\(+\) 映射类模拟是最常出的)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <algorithm>
#include <math.h>
#include <vector>
using namespace std;
const int N=1e3+7;
int a[N];//标签i的次数
int main(){
	int n;
	cin>>n;
	while(n--){
		int k;
		cin>>k;
		while(k--){
			int val;
			cin>>val;
			a[val]++; 
		} 
	} 
	int ans=0;
	for(int i=1;i<=1000;i++){
		ans=max(ans,a[i]);
	}
	int id=0
	for(int i=1;i<=1000;i++){
		if(a[i]==ans){
			id=i;
		}
	}
	cout<<id<<" "<<ans;
} 

L1-035 情人节

​ 简单模拟。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include <algorithm>
#include <math.h>
#include <vector>
using namespace std;
const int N=1e3+7;
string s[N];
string t;
int main(){
	for(int i=1;;i++){
		cin>>t;
		if(t=="."){
			if((i-1)<2){//前面已经有了(i-1)个人 如果少于2的话就是这种情况
				cout<<"Momo... No one is for you ...";
			}	
			else if((i-1)<14){
				printf("%s is the only one for you...",s[2].data());
			}
			else{
				printf("%s and %s are inviting you to dinner...",s[2].data(),s[14].data());	
			}
			break;
		}
		else{
			s[i]=t;
		}
	}
}

L1-036 A乘以B

​ 太简单就不贴了

L1-037 A除以B

​ 小考了一下格式输出。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <algorithm>
#include <math.h>
#include <vector>
using namespace std;
const int N=1e3+7;
string s[N];
string t;

int main(){
	double a,b;
	cin>>a>>b;
	cout<<a<<"/";
	if(b<0)cout<<"(";
	cout<<b;
	if(b<0)cout<<")";
	cout<<"=";
	if(!b){
		cout<<"Error";
		return 0;
	}
	printf("%.2lf",a/b);
}

L1-038 新世界

​ 记得用python做

1
2
print("Hello World")
print("Hello New World")

L1-039 古风排版

​ 一个比较考察思维的模拟题,对字符串处理也有些。

​ 首先与其思考\(s[i][j]\) 在原字符串哪个位置,不如将\(s[i][j]\) 的遍历顺序改成顺着原字符串位置进行赋值遍历,这样就无需考虑原字符串到底是什么,观察样例可知这是一个\(i\) 逆序,\(j\) 顺序,从\(s[j][i]\) 开始赋值的数组,之类要特别处理\(m\) 为行数,如果字符串长度不够要补多1位,然后按位置顺着赋值就可以了,如果字符串赋值完了,我们就赋为空格即可。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <cstring>
using namespace std;
const int N=107;
char s[N][N];
string t;
int vis[N][N];
int main(){
	int k,kk;
	cin>>k;//行 
	getchar(); 
	getline(cin,t);	
	int n=t.size(); 
	int m=n/k+(n%k==0?0:1);//列数
	int p=0;//作为指针
	for(int i=m;i>=1;i--){
		for(int j=1;j<=k;j++){
			if(p>=n){
				s[j][i]=' ';
				continue;
			}
			s[j][i]=t[p];
			p++;
		}
	}
	for(int i=1;i<=k;i++){
		for(int j=1;j<=m;j++){
			cout<<s[i][j];
		}
		if(i!=k)cout<<endl;
	} 
    return 0;
}

L1-040 最佳情侣身高差

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
int main(){
	int tt;
	cin>>tt;
	while(tt--){
		char c;
		double p;
		cin>>c>>p;
		if(c=='M'){
			printf("%.2lf",p/1.09);
		}
		else printf("%.2lf",p*1.09);
		printf("\n");
	}
}

L1-041 寻找250

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
int main(){
	int cnt=1;
	while(1){
		int val;
		cin>>val;
		if(val==250){
			cout<<cnt;
			return 0;
		}
		cnt++;
	}
}

L1-042 日期格式化

​ 小考了一下格式化读入和格式化输出。

1
2
3
4
5
int main(){
	int y,m,d;
	scanf("%d-%d-%d",&m,&d,&y);
	printf("%04d-%02d-%02d",y,m,d);
}

L1-043 阅览室

​ 一个比较麻烦的模拟题,这里注意四舍五入的写法。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <iostream>
using namespace std;
const int N=1e4+7;
struct node{
	int st;
	int flag;
}a[N];

int n;

int get(int h,int m){
	return h*60+m;
}

int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		int totalTime=0; //当天的总阅读时间 
		int cnt=0;//当天借阅书本数量
		for(int j=1;j<=1000;j++)a[i].flag=0;
		int id,hour,minute;
		char c; 
		while(1){
			scanf("%d %c %d:%d",&id,&c,&hour,&minute);//书本编号 借/还 时 分
			if(id==0)break;//结束一天
			if(c=='S'){ //借阅 
				a[id].st=get(hour,minute);
				a[id].flag=1;
			}
			else{
				if(a[id].flag==0)continue;
				totalTime+=get(hour,minute)-a[id].st;
				cnt++;
				a[id].flag=0;
			}
		}
		if(cnt==0)puts("0 0");
		else{
			int avg=(int)totalTime*1.0/cnt+0.5;
			cout<<cnt<<" ";
			cout<<avg<<"\n";
		}
	}
} 

L1-044 稳赢

\(2023\) 年天梯赛模拟赛的原题,其实就是个很简单的模拟,但注意每隔\(k\) 次就平,指的是第\(k+1\) 要平。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
#include <algorithm>
#include <math.h>
#include <vector>
#include <cstring>
using namespace std;
string win(string s){
	if(s=="ChuiZi")return "Bu";
	if(s=="JianDao")return "ChuiZi";
	else return "JianDao"; 
}

int main(){
	ios::sync_with_stdio(false),cin.tie(0);
	int k;
	cin>>k;
	for(int i=1;;i++){
		string s;
		cin>>s;
		if(s=="End")break;
		if(i%(k+1)==0){
			cout<<s<<endl;
		}
		else cout<<win(s)<<endl;
	}
	return 0;
}

L1-045 宇宙无敌大招呼

1
2
name=input()
print("Hello %s"%(name))

L1-046 整除光棍

​ 注意到枚举\(1,11,111,..\) 满足题设\(x*s=k\) ,即判断\(k\%s=0\) 的话就能得到\(x=k/s\) ,但数据量有时候特别大,直接输出\(k/s\) 会超时,考虑大数除法(这个知识点来源于高精度,如果你没有学过请百度)

​ 或者考虑模拟竖式除法,我们先看看\(111/13\) 是个怎么回事

image-20230429005911051

​ 然后发现这个不是我们所要的,那我们计算\(1111/13\) 是怎么弄的?

image-20230429010019780

​ 那我们发现其实\(1111/13='8'+(111\%13)*10+1/13\) ,只需要将\(8\) 拼接一下余数加\(1\) 的数字再除除数就可以了!(不懂的话多列几个),这样不仅避免了几百个\(1\) 导致的数字巨大,也避免了除法的超时

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include <vector>
using namespace std;


int main(){
	int n;
	cin>>n;
	int k=1;
	int cnt=0;
	while(k<n){
		k=k*10+1;
		cnt++;		
	}
	while(1){
		cout<<k/n;
		int m=k%n;
		if(m==0){
			cnt++;break;
		}
		else{
			k%=n;
			k=k*10+1;
			cnt++;
		}
	}
	cout<<" "<<cnt;
} 

​ 作为算法竞赛选手,是否能推出普遍性?

​ 推论:为方便表示,称\(n\)\(k\) 组成的数字是\(K_n\) ,假设\(K_n\) 可以被\(b\) 整除,并且\(a/b\)代表\(a\)\(b\)向下取整,则有\(K_n/b=K_{n-1}/b*10+((K_{n-1}\%b)*10+K_1)/b\) ,若不可整除,余数为:\(((K_{n-1}\%b)*10+K_1)\%b\)

​ 证明:由于\(K_n=K_{n-1}*10+K_1\) ,将\(K_{n-1}\) 分为可整除部分\(P_{n-1}\) 和余数部分\(M_{n-1}\) ,则两边同时除\(b\) 得到\((P_{n-1}+M_{n-1})*10/b+K_1/b\) ,化简得到:\(P_{n-1}*10/b+M_{n-1}*10/b+K_1/b\) ,最终化简得到式子:\(P_{n-1}*10/b+(M_{n-1}*10+K_1)/b\) ,与原式定义相同。

我闲的没事证明这个干什么,考试时候推出来不就行了 ,确实是这样,但考试瞬息万变,像刚刚的式子你很难一步就到位,不说手算模拟过程,代码过程都很大概率会出错,用严谨的办法证明是一来保证自己做的确实对了,二来是在以后用到类似的结论能用上。

L1-047 装睡

​ 简单的范围判断题,连模拟题都算不上。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#include <iostream>
using namespace std;
int main(){
    int n;
    cin>>n;
    while(n--){
       string s; 
       int a,b;
       cin>>s>>a>>b;
       if(a<15||a>20||b<50||b>70){
       		cout<<s<<endl;
	   }
    }
    return 0;
}

L1-048 矩阵A乘以B

​ 这题涉及到线性代数的知识。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
using namespace std;
const int N=600;
int a[N][N];
int b[N][N];
int c[N][N];
int ra,ca,rb,cb;
int main(){
	cin>>ra>>ca;
	for(int i=1;i<=ra;i++){
		for(int j=1;j<=ca;j++){
			cin>>a[i][j];
		}
	}
	cin>>rb>>cb;
	if(ca!=rb){ //内标不相同 
		printf("Error: %d != %d",ca,rb);
		return 0;
	}
	for(int i=1;i<=rb;i++){
		for(int j=1;j<=cb;j++){
			cin>>b[i][j];
		}
	}
	int rc=ra,cc=cb;
	cout<<rc<<" "<<cc<<"\n";
	for(int i=1;i<=rc;i++){
		for(int j=1;j<=cc;j++){
			for(int k=1;k<=ca;k++){
				c[i][j]+=a[i][k]*b[k][j];//矩阵乘法公式
			}
			if(j!=1)cout<<" ";
			cout<<c[i][j];
		}
		cout<<"\n";
	}
	return 0;
}

L1-049 天梯赛座位分配

​ 算的上比较有意思的找规律,赛时真出的话说不定能调一小时,可以用码量暴力AC

​ 注意到分配座位是逐个逐个分配的,如果上一次分配的座位号所给的学校与本次准备分配的座位号所属的学校是一样的话,那就说明剩余分配号数都在校内了,需要加多一次,定义\(last\) 为上一次分配的座位号所属学校的编号。

​ 坑点有\(2\)\((1)\) 要注意给号的顺序,理解了这个才能写得出来循环顺序和范围\((2)\) 加多一次不是给当前的座位号加,而是直接加到\(cnt\) 上,否则下一次还是会使用原来的\(cnt \)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
using namespace std;
const int N=105;
int a[N][N][11];//第i个学校第j个队伍第k个人 
int n;
int list[N]; //第i个学校的参赛队伍 
int maxList=0;
int cnt;


void show(){
	for(int i=1;i<=n;i++){
		cout<<"#"<<i<<"\n";
		for(int j=1;j<=list[i];j++){
			for(int k=1;k<=10;k++){
				if(k!=1)cout<<" ";
				cout<<a[i][j][k];
			}
			cout<<"\n";
		}
	} 
} 
int main(){
	ios::sync_with_stdio(false),cin.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>list[i];
		maxList=max(maxList,list[i]);
	} 
	int last=-1;
	for(int i=1;i<=maxList;i++){ //队伍 
		for(int j=1;j<=10;j++){ //人 
			for(int k=1;k<=n;k++){ //学校 
				if(list[k]<i)continue; //如果当前学校没有这么多队伍就跳到下一个学校 
				if(last==k)cnt++;
				a[k][i][j]=++cnt;
				last=k;
			} 
		}
	}
	show();
    return 0;
}

时间复杂度:\(O(nm)\) ,其中\(m\) 代表最大队伍量。

空间复杂度:\(O(nm)\)

L1-050 倒数第N个字符串

​ 容易发现步长为\(L\) 的字符串构成的序列其实就是按字典序排序的全\(a\) 到全\(z\) ,由于长度为\(L\) ,一共有\(26^L\) 中不同的字符串,\(L\) 最大为\(7\) ,大概是\(3e8\) 左右的数据量,就算是枚举\(O(n)\) 的复杂度也很难通过,考虑性质。

​ 首先这问题其实就是「已知有\(n\) 位的\(26\)进制数,求倒数第\(k\) 个数」,显然\(zz..zz\) 就是\(26^L\) ,只需要减去就可以得到一个十进制结果,然后得到二十六进制的每一位。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include<iostream>
#include <math.h>
using namespace std;
const int N=18;
int a[N];
int l,n;
int cnt; 
long long m;
int main(){
	cin>>l>>n;
	m=pow(26,l)-1;
	n-=1;
	cnt=0;
	m-=n;
	while(m){
		int end=m%26;
		a[l-cnt]=end;
		cnt++;
		m/=26;
	}
	for(int i=1;i<=l;i++)cout<<char('a'+a[i]);
    return 0;
}

时间复杂度:\(O(log_{26}(m))\)

空间复杂度:\(O(L)\)

L1-051 打折

​ 很简单的模拟题,考察的是基本的格式输出,但注意\(K\) 折其实是\((K*10)/100=K/10\) ,价格应该是\((n*k)/10\)

1
2
3
4
5
6
7
8
9
#include <iostream>
using namespace std;

int main(){
	int n,p;
	cin>>n>>p;
	printf("%.2f",(float)(n*p)/10);
	return 0;
}

L1-052 2018我们要赢

1
2
print("2018")
print("wo3 men2 yao4 ying2 !")

L1-053 电子汪

1
2
3
4
5
6
7
8
9
#include <iostream>
using namespace std;

int main(){
	int a,b;
	cin>>a>>b;
	int k=a+b;
	while(k--)cout<<"Wang!"; 
}

L1-054 福到了

​ 一道比较有意思的循环模拟题,这题一定不要被反转过程晃晕,实际上一个数组的反转就等于他原本的第\(i\) 行变成了\(n-i\) 行的字符串,然后再颠倒一次,只需要模拟一遍就可以了。

​ 注意到不需要倒过来的过程就是转化后\(s[i]\) 仍然等于原本的\(s[i]\) ,否则就需要倒,因此开辟一个额外的数组更加方便。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
using namespace std;
const int N=107;
char c;
int n;
string s[N],b[N];
int main(){
	//ios::sync_with_stdio(false),cin.tie(0);
	cin>>c>>n;
	getchar();//注意要getchar 
	for(int i=1;i<=n;i++)getline(cin,s[i]);
	int ok=1;
	for(int i=1;i<=n;i++){
		b[i]=s[n-i+1]; //置换
		int l=0,r=b[i].size()-1;
		while(l<r){ //行内置换
			char t=b[i][l];
			b[i][l]=b[i][r];
			b[i][r]=t;
			l++,r--;
		}
		if(b[i]!=s[i]){
			ok=0;
		}
	}
	if(ok)puts("bu yong dao le");
	for(int i=1;i<=n;i++){
		for(int j=0;j<b[i].size();j++){
			if(b[i][j]!=' ')b[i][j]=c;
			cout<<b[i][j];
		}
		cout<<"\n";
	}
	return 0;
} 

L1-055 谁是赢家

​ 注意到票数少的情况下只有获取全部认可才可能赢,因此只要高票数者没得到全部票数就输出票数少的,否则就输出票数高的。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
using namespace std;

int p[2];
int pw[2];

void judge(){
	int mv=0;
	if(p[0]>p[1])mv=0;
	else mv=1;
	if(pw[mv]==0){ //如果最大值的那个没有得到任何认
		int d=!mv;
		printf("The winner is %c: %d + %d",'a'+d,p[d],3);//给较小的那个 
		return;
	}
	printf("The winner is %c: %d + %d",'a'+mv,p[mv],pw[mv]);
}

int main(){
	cin>>p[0]>>p[1];
	int k=3;
	while(k--){
		int val;
		cin>>val;
		pw[val]++;
	} 
	judge();
	return 0;
} 

L1-056 猜数字

​ 注意这里差值要用float ,因为如果平均数是\(1.2\) 而且 用整形的话,\(0\)\(2\) 到他的距离变成都是\(1\) ,但实际上\(1.2\) 到他的距离只有\(0.8\)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include<iostream>
using namespace std;
const int N=1e4+7;
int a[N];
int n;
double avg;
string name[N];
double ans=0x3f3f3f3f;
int ansId;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>name[i]>>a[i];
		avg+=a[i];
	}
	avg/=2*n;
	cout<<(int)avg<<" ";
	for(int i=1;i<=n;i++){
		double d=a[i]-avg;
		if(d<0)d=-d;
		if(d<ans){
			ansId=i;
			ans=d;
		}
	}
	cout<<name[ansId];
} 

L1-057 PTA使我精神焕发

1
print("PTA shi3 wo3 jing1 shen2 huan4 fa1 !")

L1-058 6翻了

​ 由于修改字符串会导致\(s.size()\) 和下标遍历不准确,所以直接考虑输出,遍历到\(6\) 的时候记录,然后到非\(6\) 的字符就将之前存储的结果按要求输出就行了,但注意到有可能最后末尾是一个连续的\(6\) 存储了没来得及到一个非\(6\) 的字符就结束了,所以结束后要特判一下。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
using namespace std;

int main(){
	string s;
	getline(cin,s);
	int n=s.size();
	int cnt=0;
	for(int i=0;i<n;i++){
		if(s[i]=='6'){
			cnt++;
		}
		else{
			if(cnt>9)cout<<"27";
			else if(cnt>3)cout<<"9";
			else while(cnt--)cout<<"6";
			cnt=0;
			cout<<s[i];
		}
	}
	if(cnt){
		if(cnt>9)cout<<"27";
		else if(cnt>3)cout<<"9";
		else while(cnt--)cout<<"6";
	}
	return 0;
}

L1-059 敲笨钟

​ 注意到并不是有两个ong 就能修改,例如\(s=an\ ong\ ong,\ a\ b \ c.\) 就不行,所以观察输入格式可知,只有逗号前和点号有ong 才是可修改的,那具体怎么修改呢?

​ 每个词之间都有一个空格,所以只需要找到倒数第三个空格,从这个位置往后全修改成qiao ben zhong. 就可以了(注意不要把空格本身也换了,所以是\(+1\)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
using namespace std;
const int N=24;
string s[N];
int n;

int check(int i){
	int p1=s[i].find("ong, ");
	int p2=s[i].find("ong.");
	return p1!=-1&&p2!=-1;
}

int main(){
	cin>>n;
	getchar();
	for(int i=1;i<=n;i++){
		getline(cin,s[i]);
	}
	for(int i=1;i<=n;i++){
		if(check(i)==0){
			puts("Skipped");
			continue;
		}
		//校验 
		int j;
		int cnt=0;
		for(j=s[i].size()-1;j>=0;j--){
			if(s[i][j]==' ')cnt++;
			if(cnt==3){
				break;
			}
		}
		s[i].replace(j+1,s[i].size()-j-1,"qiao ben zhong.");
		cout<<s[i]<<endl;
	}
}

L1-060 心理阴影面积

​ 先求出大三角面积,然后分别减去两个蓝色三角形和一个红色矩形就可以了。

image-20230701111548165

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#include <iostream>
using namespace std;

int get(int d,int h){
	return d*h/2;
}
int x,y;
int main(){
	cin>>x>>y;
	int A=get(100,100);//大三角形 
	int B=get(100-x,100-y);//靠上的那个三角形
	int C=get(x,y);//倒下的那个三角形 
	int D=(100-x)*y;//矩形 
	cout<<A-B-C-D; 
}

L1-061 新胖子公式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#include <iostream>
using namespace std;

int main(){
	double h,w;
	cin>>w>>h;
	double result=w/(h*h);
	printf("%.1f\n",result);
	if(result>25.00){
		puts("PANG");
	}
	else puts("Hai Xing");
}

L1-062 幸运彩票

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
using namespace std;

int main(){
	int tt;
	cin>>tt;
	while(tt--){
		string s;
		cin>>s;
		int l=0,r=0;
		for(int i=0;i<3;i++)l+=s[i]-'0';
		for(int i=s.size()-1;i>=s.size()-3;i--)r+=s[i]-'0';
		if(l==r){
			puts("You are lucky!");
		}
		else puts("Wish you good luck.");
	}
	
}

L1-063 吃鱼还是吃肉

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
using namespace std;
int a[2][2];
int main(){
	int tt;
	cin>>tt;
	a[1][0]=130;
	a[1][1]=27;
	a[0][0]=129;
	a[0][1]=25;
	while(tt--){
		int id,h,w;
		cin>>id>>h>>w;
		if(h>a[id][0]){
			cout<<"ni li hai! ";
		}
		else if(h<a[id][0])cout<<"duo chi yu! ";
		else cout<<"wan mei! ";
		//
		if(w>a[id][1]){
			cout<<"shao chi rou!";
		}
		else if(w<a[id][1])cout<<"duo chi rou!";
		else cout<<"wan mei!";
		puts("");
	}
	
}

L1-064 估值一亿的AI核心代码

​ 一道非常麻烦的模拟题,但也很考验字符串处理。但如果这题使用正则表达式处理的话就会非常简单,前提是你能写出正则表达式。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include<bits/stdc++.h>
using namespace std;
int main(){
    int n;
    string s;
    cin>>n;
    getchar();
    while(getline(cin,s)){
        cout<<s<<endl<<"AI: ";
        s=regex_replace(s,regex(R"(\s+)")," ");
        //将连续的空格换成单个空格
        s=regex_replace(s,regex(R"(^\s+|\s+$|\s+(?=\W))"),"");
        //去除头尾的空格和标点符号前的空格
        s=regex_replace(s,regex(R"(\bI\b)"),"mark_mark");
        //为了防止冲突先将I置换成一个特殊标识
        for(int i=0;i<s.size();i++)
            if(s[i]!='I')s[i]=tolower(s[i]); //小写化
        s=regex_replace(s,regex(R"(\bcan you\b)"),"I can");
        //\b表示单词边界,这样可以替换独立的can you
        s=regex_replace(s,regex(R"(\bcould you\b)"),"I could");
        //同理
        s=regex_replace(s,regex(R"(mark_mark|\bme\b)"),"you");
        //把原来的I替换成you即可。
        s=regex_replace(s,regex(R"(\?)"),"!");
        //把问号替换成感叹号
        cout<<s<<endl;
    }
    return 0;
}

L1-065 嫑废话上代码

1
print("Talk is cheap. Show me the code.")

L1-066 猫是液体

1
2
3
4
5
6
7
8
#include <iostream>
using namespace std;

int main(){
	int a,b,c;
	cin>>a>>b>>c;
	cout<<a*b*c;
}

L1-067 洛希极限

​ 题目挺绕的,但也考察了下数学。

​ 意思是一开始给了一个值\(B_3\) ,他乘上大天梯的半径\(R_b\) 和一个常数\(k\) 后,得到的就是洛希极限,然后现在再给\(n=\frac{天体距离}{R_b}\) ,求洛希极限是否大于天体距离。

​ 虽然\(R_b\) 没给,但洛希极限\(L_m=B_3R_bk\) ,天体距离\(=R_b*n\) ,两者可以约掉未知的\(R_b\) ,所以只需要判断\(B_3k>or 即可,这些都是已知的。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#include <iostream>
#include <math.h>
using namespace std;
double d[2]={2.455,1.26};
int main(){
	double kf,distant;
	int id;
	cin>>kf>>id>>distant;
	double res=kf*d[id];
	printf("%.2f ",res);
	if(distant>=res){
		puts("^_^");
	}
	else puts("T_T");
	return 0;
}

L1-068 调和平均

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#include <iostream>
using namespace std;
const int N=1007;
int a[N];

int main(){
	int n;
	double sum=0;
	cin>>n;
	for(int i=1;i<=n;i++){
		double val;
		cin>>val;
		val=1/val;
		sum+=val;
	}
	sum/=n;
	printf("%.2lf",1/sum);
} 

L1-069 胎压监测

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
using namespace std;
const int N=5;
int a[N];
int maxv;
int d,minv;
int need;
int main(){
	for(int i=1;i<=4;i++){
		cin>>a[i];
		maxv=max(maxv,a[i]);
	}
	cin>>minv>>d;
	int cnt=0;
	for(int i=1;i<=4;i++){
		if(maxv-a[i]>d||a[i]<minv){
			cnt++;
			need=i; 
		}
	}
	if(cnt==0)puts("Normal");
	else if(cnt==1)printf("Warning: please check #%d!",need); 
	else printf("Warning: please check all the tires!");
	
} 

L1-070 吃火锅

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
using namespace std;
const int N=5;
int fi;
int main(){
	int ok=0;
	string s;
	int i=0;
	int cnt=0;
	while(getline(cin,s)&&s!="."){
		i++;
		if(s.find("chi1 huo3 guo1")!=-1){
			if(!ok){
				fi=i;
				ok=1;
			}
			cnt++;
		}
	}
	cout<<i<<"\n";
	if(!ok)puts("-_-#");
	else cout<<fi<<" "<<cnt;
	
} 

L1-071 前世档案

​ 我们把否看成\(1\) ,把是看成\(0\) ,显然结论\(x\) 就是选择序列的十进制表示。

​ 这里可以用bitset 来转化进制,比较方便,注意结论是\(1\) 开始的,但转化的十进制最低是\(0\) ,所以要加\(1\)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <bitset>
using namespace std;

int main(){
	int n,m;
	cin>>n>>m;
	while(m--){
		string s;
		cin>>s;
		for(int i=0;i<s.size();i++){
			if(s[i]=='n')s[i]='1';
			else s[i]='0';
		} 
		bitset<31> b(s);
		unsigned long long sum=b.to_ulong();
		cout<<sum+1<<"\n";
	}

} 

L1-072 刮刮彩票

L1-074 两小时学完C语言

1
2
n,m,k=map(int,input().split())
print(n-m*k)

L1-079 天梯赛的善良

​ (前面和后面有些题目没写是因为太简单或太恶心,没有学习价值)

​ 注意有可能最大最小值都是一个值,所以用if-if 而不是if-else if

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <bitset>
using namespace std;
const int N=2e4+7;
int a[N];
int maxval=-1;
int minval=1e6+1;
int maxc,minc;
int main(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		if(a[i]>maxval)maxval=a[i];
		if(a[i]<minval)minval=a[i];
	}
	for(int i=1;i<=n;i++){
		if(a[i]==maxval)maxc++;
		if(a[i]==minval)minc++;
	}
	cout<<minval<<" "<<minc<<"\n";
	cout<<maxval<<" "<<maxc<<"\n";
	return 0;
} 

L1-080 乘法口诀数列

​ 小考了一下STL和to_string()

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int f1, f2, n;

int main() {
	cin >> f1 >> f2 >> n;
	vector<int> a(2);
	a[0] = f1, a[1] = f2;
	for (int i = 0;a.size() < n;i++) {
		int val = a[i] * a[i + 1];
		string v = to_string(val);
		for (auto c : v) {
			int k = c - '0';
			a.push_back(k);
		}
	}
	for (int i = 0;i < n-1;i++) {
		cout << a[i] << " ";
	}
	cout << a[n - 1];
	return 0;
}

L1-083 谁能进图书馆

​ 注意好分类

​ 二者都可以入馆,二者都不可以入馆,二者一人是成年人另一个人可以入馆,二者一人不成年但可以入馆

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <bits/stdc++.h>
using namespace std;
int main(){
	int n,m,a,b;
	cin>>n>>m>>a>>b;
	if(a<n&&b<n)//1、都不能进 
	{
		cout<<a<<"-N"<<" "<<b<<"-N"<<endl;//格式要正确
	    cout<<"zhang da zai lai ba";
	}
	if(a>=n&&b>=n)//2、都可以进
    {
		cout<<a<<"-Y"<<" "<<b<<"-Y"<<endl;
	    cout<<"huan ying ru guan";
	}
	if(a<n&&(b>=n&&b<m))//3、一个人能进一个不能
    {
		cout<<a<<"-N"<<" "<<b<<"-Y"<<endl;
	    cout<<"2: huan ying ru guan";
	}
	if(b<n&&(a>=n&&a<m))//3、一个人能进一个不能
    {
		cout<<a<<"-Y"<<" "<<b<<"-N"<<endl;
	    cout<<"1: huan ying ru guan";
	}
	if(a<n&&b>=m)//4、两个人必须一起进
    {
		cout<<a<<"-Y"<<" "<<b<<"-Y"<<endl;
	    cout<<"qing 2 zhao gu hao 1";
	}
	if(b<n&&a>=m)//4、两个人必须一起进
    {
		cout<<a<<"-Y"<<" "<<b<<"-Y"<<endl;
	    cout<<"qing 1 zhao gu hao 2";
	}
	return 0;
}

L1-085 试试手气

本题来自\(2023\) 天梯赛模拟赛题目

​ 设\(a[i][j]\) 为第\(i\) 个骰子是否过数字\(j\) ,逆序枚举贪心即可。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int a[7][7];
int main(){
	int n;
	for(int i=1;i<=6;i++){
		int val;
		cin>>val;
		a[i][val]=1;
	}
	cin>>n;
	for(int k=1;k<=n;k++){
		for(int i=1;i<=6;i++){
			for(int j=6;j>=1;j--){
				if(a[i][j]==0){
					a[i][j]=1;
					if(k==n)cout<<j<<(i==6?"":" ");
					break;
				}
			}
		}
	}
} 

L1-086 斯德哥尔摩火车上的题

​ 简单模拟一下,注意题意。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int a[7][7];


string get(string s){
	s="'"+s;
	string ans="";
	for(int i=1;i<s.size();i++){
		int v1=s[i]-'0';
		int v2=s[i-1]-'0';
		if(v1%2==v2%2)ans+=max(v1,v2)+'0';
	}
	return ans;
}
int main(){
	string a,b;
	cin>>a>>b;
	string ta=get(a);
	string tb=get(b);
	cout<<ta<<"\n";
	if(ta!=tb){
		cout<<tb;
	}
} 

L1-087 机工士姆斯塔迪奥

​ 很有意思的容斥计数问题,算是模拟题中比较正常的一道了。

​ 显然boss没放技能的时候一共有\(n\times m\) 个格子是安全的,当boss往一列攻击时,有\(n\) 个格子不安全,往一行攻击时有\(m\)个格子不安全,当他往一列攻击时,必定会和\(k\) 个已经攻击的行产生\(k\) 个交错点,我们要删去这个点,不妨设攻击了\(k\) 个行,\(l\) 个列,即答案为:\((n\times m)-(n\times l)+(m\times k)+(k\times l) \)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int N=1e5+7;
int row[N];
int col[N];
int main(){
	int n,m,q;
	cin>>n>>m>>q;
	long long ans=1LL*n*m;
	int k=0,l=0;
	while(q--){
		int v,c;
		cin>>v>>c;
		if(v==0){
			if(row[c])continue; //如果已经被攻击过就不要处理
			row[c]=1;
			k++;
		}
		else{
			if(col[c])continue;
			col[c]=1;
			l++;
		}
	}
	ans-=1LL*k*m;
	ans-=1LL*l*n;
	ans+=1LL*k*l;
	cout<<ans;
	return 0;
	
}

L1-088 静静的推荐

​ 比较难的是批次问题,我们尽可能让一个批次的人更优,

​ 如果一个人成绩达标了并且PAT也达标了就直接录入,如果PAT不达标,就要和同分数的人进行抉择,如果当时同分数的人不超过\(k\) 个,就说明可以成为一个批次录入进去。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int N=1e5+7;
int vis[N];
	
int main(){
	int n,k,s;
	cin>>n>>k>>s;
	int cnt=0;
	for(int i=1;i<=n;i++){
		int tts,pat;
		cin>>tts>>pat;
		if(tts<175)continue;
		if(pat>=s){ //天梯赛达标了 
			cnt++;
		}
		else if(vis[tts]<k){ //天梯赛不达标{
			cnt++;
			vis[tts]++;
		}
	}
	cout<<cnt;
}

L1-089 最好的文档

本题来自\(2023\) 天梯赛正式赛题目。

1
print("Good code is its own best documentation.")

L1-090 什么是机器学习

本题来自\(2023\) 天梯赛正式赛题目

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#include <iostream>
using namespace std;

int main(){
	int a,b;
	cin>>a>>b;
	int s=a+b;
	cout<<s-16;
	cout<<"\n";
	cout<<s-3;
	cout<<"\n";
	cout<<s-1;
	cout<<"\n";
	cout<<s;
}

L1-091 程序员买包子

本题来自\(2023\) 天梯赛正式赛题目,比赛的时候题意我没看,我直接看输出格式,按输出格式输出就可以了

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#include <iostream>
using namespace std;

int main(){
	int n,m,k;
	string x;
	cin>>n>>x>>m>>k;
	if(k==n){
		printf("mei you mai %s de",x.data());
	}
	else if(k==m){
		printf("kan dao le mai %s de",x.data());
	}
	else{
		printf("wang le zhao mai %s de",x.data());
	}
}

L1-092 进化论

本题来自\(2023\) 天梯赛正式赛题目,比赛的时候题意我没看,我直接看输出格式,按输出格式输出就可以了

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
using namespace std;

int main(){
	int tt;
	cin>>tt;
	while(tt--){
		int a,b,c;
		cin>>a>>b>>c;
		int s=a*b;
		int p=a+b;
		if(c==s){
			puts("Lv Yan");
		}
		else if(c==p){
			puts("Tu Dou");
		}
		else puts("zhe du shi sha ya!");
	}
}

L1-093 猜帽子游戏

本题来自\(2023\) 天梯赛正式赛题目,稍微需要动动脑子的模拟

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
using namespace std;
const int N=103;
int hat[N];
int main(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>hat[i];
	}
	int k;
	cin>>k;
	for(int i=1;i<=k;i++){
		int flag=1;
		int one=0;
		for(int j=1;j<=n;j++){
			int val;
			cin>>val;
			if(val)one=1;
			if(val&&val!=hat[j])flag=0;
		}
		if(one&&flag)puts("Da Jiang!!!");
		else puts("Ai Ya");
	}
} 

L1-094 剪切粘贴

本题来自\(2023\) 天梯赛正式赛题目,很恶心的字符串处理题,我赛时一直在调这道题,最终也没调出来,赛后看了下string 的方法复习了一下10分钟就做出来了,痛失\(15\)

​ 删除操作:考察了字符串的定向删除,删除区间\([l,r]\) ,实际上就是s.erase(l,r-l+1) ,然后先用子串函数把删去的内容获取出来

​ 添加操作:先用s.find 子串匹配,然后得到\(pos\) 加上字符串长度就是字符串\(A\) 的下一个位置,如果这个位置往后\(b.size()\) 的字符不是\(b\) 的话,那说明不匹配,找到下一个\(pos\) ,如果到最后也没找到符合的位置,就尾插。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>
using namespace std;
string s, last;
int n;
//s.erase(i,k) 删除下标i开始的k个字符(包括i)
void cut(int l, int r) {
	last = s.substr(l, r - l + 1);//把要删的内容赋值到剪切板字符串上 
	s.erase(l, r - l + 1);//删除区间[l,r]的函数,等价于删除l开始的r-l+1个字符 
	return;
}
void add(string a, string b) {
	int p = 1;
	while (p != -1) { //不断寻找符合A的pos 
		p = s.find(a, p);
		if (p == -1)break;//找不到了就退了
		p += a.size();//加上pos就是A串往后一个位置 
		int bs = b.size();//这个位置加上b的长度 
		if (s.substr(p,bs)==b) {//如果往后长度与b相同的串并不是B 说明A能匹配但B匹配不上 
			s.insert(p, last);//找到就插入 
			return; 
		}
		else continue;//否则就继续找下一个pos 
	}
	s += last;//否则尾插 
	return;
}
int main() {
	cin >> s;
	s = "/" + s;//字符串编号从1开始,加个前置符号 
	cin >> n;
	while (n--) {
		int l, r;
		string a, b;
		cin >> l >> r >> a >> b;
		cut(l, r);
		add(a, b);
	}
	s.erase(0,1);//把前置的符号删了 
	cout << s;//打印
	return 0; 
}

L1-095 分寝室

​ 本题来自\(2023\) 天梯赛正式赛题目,算是有点难度的题目了。

​ 考虑枚举女生宿舍住\(i\) 个人,男生宿舍每间住\(j\) 个人,然后双层枚举每一种搭配情况

​ 注意到如果如果装不满(也就是\(人数/房间承载量\) 有余数)的话就不能用,反过来思考,虽然我们枚举了从\(2\)\(woman\) (最富裕的情况就是\(2\) 个人一间,最穷的情况就是所有人住一间),但只有满足\(woman\%i=0\) 的方案才会继续循环,也就是虽然外层复杂度是\(O(woman)\) ,但进入内层的只有\(woman\) 的因子个,观察规模可得最多也就\(10^5\) ,其因子个数大约一百来个,即使是\(O(10^5*10^2)=O(10^7)\) 也能过。记得用变量记录一下两者最大差值,然后记得更新就可以了。

​ 这里可以做个总结:不要看到\(10^4\) 就感觉两层循环不行,两层\(for\) 虽然绝大意义上来讲都是\(O(n^2)\) ,但在一些有跳过,终止的循环中,其复杂度可以锐减到\(O(n*k)\)

​ 一个小优化。若\(i\) 固定时且比\(j\) 小,已经发生了\(j-i>db\) ,那往后的\(j\) 不可能比这个答案更优, 因为\(j\) 更大而\(i\) 不变时,绝对值只会更大,所以直接推掉就行,但实际上理论复杂度并没有因此下降。

​ 或者考虑更优化的情况,我们初始化woman和man的因子集合,这样做的时间复杂度是:\(O(\sqrt n +k^2)\) ,其中\(k\) 为因子的个数,可以证明的是\(k\) 不会超过\(10^3\)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
using namespace std;

int main(){
	int n,woman,man;
	cin>>woman>>man>>n;
	int db=0x3f3f3f3f;
	int ansx;
	int ansy;
	for(int i=2;i<=woman;i++){
		if(woman%i!=0)continue;
		for(int j=2;j<=man;j++){
			if(man%j!=0)continue;
			int womanuse=woman/i,manuse=man/j;
			if(womanuse+manuse==n&&abs(i-j)<db){
				db=abs(i-j);
				ansx=womanuse,ansy=manuse;
			}
		}
	}
	if(db==0x3f3f3f3f){
		puts("No Solution");
	}
	else cout<<ansx<<" "<<ansy;
} 

L1-096 谁管谁叫爹

​ 考了数位取值吧,然后就是一个很简单的模拟。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include<iostream>
using namespace std;

int get(int x){
	int ans=0;
	while(x){
		int end=x%10;
		ans+=end;
		x/=10;
	}
	return ans;
}


int main(){
	int tt;
	cin>>tt;
	while(tt--){
		int na,nb;
		cin>>na>>nb;
		int sa=get(na);
		int sb=get(nb);
		int af=na%sb;
		int bf=nb%sa;
		if(!af&&bf)puts("A");
		else if(!bf&&af)puts("B");
		else cout<<(na>nb?"A":"B")<<endl;
	}
	
}
comments powered by Disqus
Built with Hugo
主题 StackJimmy 设计