记录“哈尔滨理工大学21级新生程序设计竞赛(同步赛)”中的问题
C-kiki和bob玩取石子
题目描述
kiki和bob在玩一个游戏,他们收集了一些石子,约定两人轮流从这些石子中取出一部分,但是每次只能取1、2或3颗石子,无法继续取的人输了,kiki和bob都非常聪明,他们总是按照最有利于自己的方式进行游戏,请你预测最后谁会赢得游戏,如果先手胜利输出kiki,否则输出bob。
输入描述:
输入一个整数n(1<=n<=10^9)代表一共有多少颗石子。
输出描述:
如果先手胜利输出kiki,否则输出bob。
示例1
输入
10
输出
kiki
示例2
输入
8
输出
bob
题解:谁先取到最后一颗石子算谁赢。
一开始一头雾水,不知道从哪里开始,也不明白题目描述所说总是按照最有利于自己的方式进行游戏是什么意思。
看了题解之后,发现代码原来是如此简单。
学会从最简单的数据开始找规律!
当有1、2、3个石子时 ,kiki一次性全拿走,获胜
当有4个石子时,无论先手拿几个,下一个人必定能拿走剩下所有石子
当有5、6、7个石子时,先手分别拿走1、2、3个石子,能剩下4颗石子,最后先手赢
当有8个石子时,先手输
总结:到谁拿时,剩下石子为4的倍数,则对方赢。
因为双方都是按照有利于自己的方式进行游戏,所以当石子个数不是4的倍数时,先手可以想办法拿走石子使石子个数成为4的倍数,则先手赢。而当石子个数为4的倍数时,先手不管拿走多少,都会让对方拿走石子产生剩下石子个数为4的倍数的情况。
代码:
#include <bits/stdc++.h>
using namespace std;
//write your code,learn something a day,and make progress every day!
long long n;
int main(){
scanf("%d",&n);
if(n%4)
printf("kiki");
else
printf("bob");
return 0;
}
D-猴王kiki分桃
题目描述
猴王kiki有一天在山上发现了一大片桃树林,树上结了数不清的桃子,他打算摘一些桃子回去分给小猴子们,算上猴王一共有n个猴子。
但kiki体力有限,最多能拿R个桃子回去。但是拿的太少又不够分的,所以他至少要拿L个桃子回去。保证 n ≤L≤R。
也就是说,kiki如果摘了k个桃子,那么需要保证 L ≤k ≤R。
kiki把这k个桃子放到篮子里,并要求大家按照如下方案分桃子:
只要篮子里有不少于n个桃子,n个猴子(包括kiki)都从篮子
中拿走恰好一个桃子,直到篮子里的桃子数量少于n块。此时篮子里剩余的桃子均作为奖励归猴王kiki所有。
作为猴王,他希望得到奖励的桃子数量(不是得到的总数)尽可能多;因此你需要写一个程序,依次输入 n, L, R,并输出
出猴王最多能获得多少作为摘桃子奖励的桃子数量。
输入描述:
输入一行,包含三个正整数 n, L, R(2 ≤ n ≤ L ≤ R ≤ 109), 分别表示猴子的个数、桃子数量的下界和上界。
输出描述:
输出一行一个整数,表示猴王kiki最多能获得多少作为摘桃子奖励的桃子数量。
示例1
输入
10 14 18
输出
8
示例2
输入
7 16 23
输出
6
题解:是一道很简单的题,但当时被我写起来有一点复杂
其实就是求L到R之间对n求余最大的余数是多少。
当n整除L和R得到结果相等时,说明此时摘的桃子越多越好,这样剩下来的更多
当不等时,说明在L和R之间有刚好可以整除n的数,则可让剩下来的桃子数等于n-1
我的代码:
#include <bits/stdc++.h>
using namespace std;
//write your code,learn something a day,and make progress every day!
long long n,L,R;
int main() {
cin>>n>>L>>R;
long long tmax,tmin;
tmax=R/n;
tmin=L/n;
for(int i=n-1;i>=0;i--){
if((i+tmin*n>=L && i+tmin*n<=R) || (i+tmax*n>=L && i+tmax*n<=R)){
cout<<i;
break;
}
}
return 0;
}
标准核心代码:
while(cin>>n>>L>>R){
if(L/n==R/n)
cout<<(R%n)<<endl;
else
cout<<(n-1)<<endl;
}
E-很二的拆分
题目描述
2022年,2月22日2时22分22秒,小二突发奇想,他认为任何一个正整数都可以拆分成若干个不同的 2 的正整数次幂,请编程帮他验证这个想法。
输入描述:
输入文件只有一行,一个正整数 𝑛(1≤ n≤ 231-1),代表需要判断的数。
输出描述:
如果这个正整数可以拆分成若干个不同的 2 的正整数次幂,从大到小输出这个拆分中的每一个数,相邻两个数之间用一个空格隔开。如果不存在这样的拆分,输出-1。
示例1
输入
7
输出
-1
示例2
输入
14
输出
8 4 2
题解:奇数不能被拆分,把偶数转成二进制即可
对比题解方法我的代码显得有点繁杂
#include <bits/stdc++.h>
using namespace std;
int b[32];
//write your code,learn something a day,and make progress every day!
int n;
int main() {
int j,i;
cin>>n;
if(n%2==1) {
cout<<"-1";
} else {
n=n/2;
for(i=1,j=0; n!=0; i++) {
if(n%2!=0){
b[j]=i;
j++;
}
n=n/2;
}
for(j-=1; j>0; j--) {
cout<<(1<<b[j])<<" ";
}
cout<<(1<<b[0]);
}
return 0;
}
标准核心代码:
if(n&1){
cout<<-1<<endl;
return 0;
}
for(int i=30;i>=1;--i){
if(n&(1<<i)) cout<<(1<<i)<<' ';
}
return 0;
F-构造字符串
题目描述
给定长度为N的字符串S,要构造一个长度为N的字符串T。T初始是空字符串。S由大写字母构成。
构造过程通过反复进行以下任意操作:
从S的头部删除一个字符,添加到T的尾部
从S的尾部删除一个字符,添加到T的尾部
请你构造出字典序尽可能小的字符串T(字典序是指首先比较第一个字符,如果不同则第一个字符
较小的字符串更小,如果相同则比较第二个字符,以此类推)
构造过程通过反复进行以下任意操作:
从S的头部删除一个字符,添加到T的尾部
从S的尾部删除一个字符,添加到T的尾部
请你构造出字典序尽可能小的字符串T(字典序是指首先比较第一个字符,如果不同则第一个字符
较小的字符串更小,如果相同则比较第二个字符,以此类推)
输入描述:
第一行一个整数N,表示字符串的长度(1<=n<=2000)
第二行输入一个长度为N的字符串S
输出描述:
输出构造出的尽可能小的字符串T
示例1
输入
6
ACDBCB
输出
ABCBCD
记录我的未通过代码:
查看代码
#include <bits/stdc++.h>
using namespace std;
//write your code,learn something a day,and make progress every day!
int n;
deque<char> dq1;
deque<char> dq2;
int main(){
cin>>n;
int t=n;
char c;
while(t--) {
cin>>c;
dq1.push_back(c);
}
while(n--) {
if(dq1.front()<=dq1.back()) {
dq2.push_back(dq1.front());
dq1.pop_front();
}
else {
dq2.push_back(dq1.back());
dq1.pop_back();
}
}
deque<char>::iterator it;
for(it=dq2.begin(); it!=dq2.end(); it++)
cout<<*it;
return 0;
}
我认为未通过的原因:没有考虑当两头字符相等时候的情况,此时不是随便取其中之一即可,因为取头还是取尾会影响接下来字符的比较
题解:
#include <bits/stdc++.h>
using namespace std;
//write your code,learn something a day,and make progress every day!
char s[2005];
int main() {
int n;
scanf("%d",&n);
int a=0,b=n-1;//标记左右端
cin>>s;
while(a<=b) {
bool left=false;
for(int i=0;a+i<=b; i++)//不明白为什么a+i<=b {
if(s[a+i]<s[b-i]) {
left=true;
break;
} else if(s[a+i]>s[b-i]) {
left=false;
break;
}
}
if(left) putchar(s[a++]);
else putchar(s[b--]);
}
return 0;
}