来源:牛客网
Nancy喜欢博弈!
Johnson和Nancy得到了一个神奇的多重集合,仅包含一个正整数n,两个人轮流进行操作。
一次操作可以将集合中一个数字分解为它的任意两个非1的因数,并加入集合中。
他们想知道,在Johnson和Nancy绝顶聪明的情况下,如果Nancy先手进行操作,最后谁没有办法继续操作了呢?
输入描述:
第一行:一个整数n。
数据满足:1≤n≤957181
输出描述:
共一行:一个字符串,表示最后谁(Johnson或者Nancy)无法进行操作。
解题思路:题目实质是求解一个数可以分解成几个素数的乘积
1.一个合数一定可以分解成有限个素数的乘积---唯一分解定理
#include <iostream>
using namespace std;
int main(){
int n;
cin>>n;
int cnt = 0;//统计n可以拆分成多少个素数
for(int i = 2; i * i <= n; i ++ ){
while(n%i==0){
cnt ++;
n/=i;
}
}
if(n!=1) cnt ++;
if(cnt%2==0) cout<<"Johnson"<<endl;
else cout<<"Nancy"<<endl;
return 0;
}
2.n/=i使得n一直在变化,是否会影响i*i<n这个判定条件?
??????????
3.正常情况下,应该是从小到大一次除以素数,为什么在循环中没有类似判定?
正常应该是2,3,5,7… 但若是除6,因为前面已经除了2,3,所以就已经不会在产生素数因子,且可以省略素数的判别过程
4.为什么最后还要判定n!=1?
如果n不等于1,那么当前的值也是n的素数因子,需要对其进行统计。
现代数学的著名证明之一是Georg Cantor证明了有理数是可枚举的。他是用下面这一张表来证明这一命题的:
我们以Z字形给上表的每一项编号。第一项是1/1,然后是1/2,2/1,3/1,2/2,…
输入描述:
整数N(1≤N≤10000000)
输出描述:
表中的第N项
解题思路:
1.找规律,先确定n是属于第几列,再根据奇偶列分别分析
#include <iostream>
using namespace std;
int main(){
int n;
cin>>n;
//先确定n是在第几列
int i;
for(i = 1; n - i > 0; i ++ ){
n-=i;
}
// 另一个判断n在第几列的写法:本质上一样的
// int i = 1;
// while((1+i)*i/2 < n){
// i ++;
// }
// n -= (1+i)*i/2 - i;
if(i%2==0){
printf("%d/%d\n", n, i + 1 - n);
}else{
printf("%d/%d\n", i + 1 - n, n);
}
return 0;
}
中国地质大学(武汉)坐落于南望山下毗邻东湖风景区。为了庆祝“华为杯”中国地质大学(武汉)第十七届ICPC程序设计大赛暨华中地区部分高校第十五届ICPC邀请赛竞赛的举办,校园中开展了许多有趣的热身小活动。 HW听到这个消息非常激动,他赶忙去参加了糖果俱乐部的活动。该活动的规则是这样的:摊位上有 n 堆糖果,第 i 堆糖果有ai 个,参与的同学可以选择其中的任意堆,当所选择糖果的总数为偶数就可以把它们都带走啦~试问通过这个活动小 HW 最多能在摊位上带走多少枚糖果。
输入描述:
第1行 输入一个整数 n(n≤100)\ n (n \leq 100) n(n≤100),代表共有 n\ n n堆糖果。
第2行 依次输入 n\ n n个整数aia_iai ( ai≤100000)(\ a_i \leq 100000)( ai≤100000),代表每堆糖果的数量。
输出描述:
输出一个整数,代表小 HW, HW最多能取得的糖果。
示例1
输入
4
1 2 3 4
输出
10
示例2
输入
8
10 11 10 10 10 10 10 10
输出
70
解题思路:1.偶数是可以全部带走的,但若存在3个奇数组,则应该是留下个数最少的组。
#include <iostream>
using namespace std;
const int N = 110;
int a[N];
int main()
{
int n;
cin>>n;
int cnt = 0;
int oddnum = 0;
int minodd = 100010;
for(int i = 1; i <= n; i ++ )
{
cin>>a[i];
cnt += a[i];
if(a[i]%2){
oddnum ++;
minodd = min(minodd, a[i]);
}
}
if(oddnum%2) cnt -= minodd;
cout<<cnt<<endl;
return 0;
}
2.刚开始存在误区,只考虑了两个奇数可以拼凑成偶数带走,忘了考虑需要带走最大的奇数。
3.小优化:其实也没有必要存储在数组中,只需要记录最小的奇数就可以了
焦虑的蚂蚁
一条长度为n的小径上,挤满了m只蚂蚁,每只蚂蚁有一个初始前进方向(向左或是向右),蚂蚁们的前进速度相同且均为1。小径的两端,均放着上了锁的箱子,箱内盛有美味的食物,蚂蚁们争相前进离开小径。不幸的是,小径十分狭窄,当两只蚂蚁相遇时,它们不得不掉头向着相反的方向前进。当所有的蚂蚁都离开小径时,锁才能够打开,蚂蚁们才能获得美味的食物。因此,蚂蚁们十分焦虑,它们想知道,到底花费多少的时间,它们才能够吃到美味的食物。你能够帮助他们解决问题吗?
输入描述:
第一行,2个整数n,m(1≤m<n≤100000,n,m均为整数),分别代表小径的长度,蚂蚁的数量。
接下来m行,每行2个数,分别代表蚂蚁的初始方向(0代表向左,1代表向右),蚂蚁的初始坐标x满足x为整数且0<x<n,蚂蚁走到坐标0或坐标n即代表离开小径。
数据保证每个坐标上最多有1只蚂蚁。数据保证给出的蚂蚁初始坐标为从小到大。
输出描述:
一行,对结果四舍五入,输出1个整数,代表蚂蚁吃到美味的食物的时间。
解题思路:
1.在碰撞前,是一只蚂蚁向左,一只蚂蚁向右,碰撞后也一只蚂蚁向左,一只蚂蚁向右。因此可以想象成两只蚂蚁灵魂互换,但身体不改变方向,也就是假设已经交换了方向,所以其实求的是所有蚂蚁走向两端的最大时间。
#include <iostream>
using namespace std;
int main(){
int len, n;
cin>>len>>n;
int ans = 0;
for(int i = 0; i < n; i ++ ){
int a, dire;
cin>>dire>>a;
if(dire==1){
a = len - a;
}
ans = max(a, ans);
}
cout<<ans<<endl;
return 0;
}
2.当方向==1时,也就代表向右走,所以走的长度应该是len-a
鹏
HtBest的小鲲长大变成了大鹏,大鹏在天际翱翔,看到了一片绵延的山脉,每座山都有自己的高度,大鹏想穿过这片山脉。由于他只能紧贴地面飞行,他想知道他一共要翻越几次大山(上升->平飞->下降,算一次,其中平飞可以没有),初始时,大鹏在山脉的左端。
输入描述:
第一行一个正整数n,表示山脉被分为n段。
第二行有n个正整数ai两两之间用空格分开,ai表示山脉第i段的高度。
输出描述:
一行,包含一个正整数,表示大鹏需要翻越几次大山。
示例1
3
1 2 1
输出
1
说明
大鹏先上升一次,再下降一次,共翻越1次。
示例2
输入
3
3 1 2
输出
0
说明
大鹏先下降一次,再上升一次,共翻越0次。
解题思路:
1.只需要在每次出现下降的时候判断前面是否是上升即可
#include <iostream>
using namespace std;
int main(){
int n;
cin>>n;
bool isascend = false;
int cnt = 0;
int a, b;
cin>>a;
for(int i = 1; i < n; i ++ ){
scanf("%d", &b);
if(b > a) isascend = true;
else if(b < a){
if(isascend) cnt ++;
isascend = false;
}
a = b;
}
cout<<cnt<<endl;
return 0;
}
2.用一个bool值记录前面是否出现上升,判断上升还是下降其实只需要两个山峰的高度即可,可以减少变量的浪费,若已经统计一次下降,记得将bool恢复
#include <iostream>
using namespace std;
int main(){
int a, b;
cin>>a>>b;
if(b > a) swap(a,b);
while(b!=0){
a = a - b;
if(b > a) swap(a,b);
}
cout<<a<<endl;
return 0;
}
求解两个数的最大公约数,每次都用较大的数减去较小的数,直到较小的数为0时,较大的数就是它们的最大公约数。
#include <iostream>
using namespace std;
int main()
{
int n;
cin>>n;
for(int i = n; i >= 0; i --){
int t;
cin>>t;
//先符号位
if(t > 0 && i != n) cout<<"+";
//再系数
if(t!=0){
if(t == 1){
if(i == 0) cout<<"1";
}
else if(t == -1) {
if(i == 0) cout<<"-1";
else cout<<"-";
}
else cout<<t;
if(i == 1) cout<<"x";
else if(i == 0){}
else cout<<"x^"<<i;
}
}
return 0;
}
解题思路:
1.题目需要考虑的分支情况比较多,容易出错
1.1 如果非最高次项系数为正,需要添加正号
1.2一次项只需要x,其他次项需要x^4类似
1.3+1和-1如果是常数项需要输出,如果不是,仅需要输出符号位
博弈与核心能源动力
ZWY最近喜欢在下课后喝酒,她说:“喝酒是人类进步的动力”。现在,便利商店推出了兑换活动。
1.两个酒瓶可以兑换1瓶酒
2.四个酒瓶盖子可以兑换1瓶酒
她先知道,在当前她所拥有的资金m和一些空酒瓶k、瓶盖g和当前酒价p已知情况下,她最多可以喝到多少瓶酒。
#include <iostream>
using namespace std;
int main(){
int ans = 0;
int m, k, g, p;
cin>>m>>k>>g>>p;
if(m > 0){
int t = m / p;
k += t;
g += t;
ans += t;
}
while(k >= 2 || g >= 4){
if(k >= 2){
int t = k / 2;
ans += t;
k = k % 2 + t;
g += t;
}
if(g >= 4){
int t = g / 4;
ans += t;
k += t;
g = g % 4 + t;
}
}
cout<<ans<<endl;
return 0;
}
已知游戏结束前场上有n个国家,第i个国家有ai块土地,任意2个国家若是想建立外交关系,则需要互相在对方的一块土地上建立一个大使馆。
一块土地只能建立一个大使馆,若一个国家和其他国家存在外交关系,则需要征用一块己方土地作为备用大使馆。
完美结局的定义是:找到最多数量的国家,使他们相互之间存在外交关系。
#include <iostream>
#include <algorithm>
using namespace std;
int a[1010];
int main(){
int T;
cin>>T;
while(T --){
int n;
cin>>n;
for(int i = 1; i <= n; i ++ ){
cin>>a[i];
}
sort(a + 1, a + n + 1, greater<int>());
int ans = 0;
for(int i = 1; i <= n; i ++ ){
if(a[i]<i) break;
ans = i;
}
cout<<ans<<endl;
}
return 0;
}
解题思路:
1.将数组从大到小排列,只要第i个国家的土地个数大于等于i,也就代表满足建立大使馆的条件
[NOIP2006]明明的随机数
明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了N个1到1000之间的随机整数(N ≤ 100),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着不同的学生的学号。然后再把这些数从小到大排序,按照排好的顺序去找同学做调查。请你协助明明完成“去重”与“排序”的工作。
解题思路:先去重后排序
#include <iostream>
#include <algorithm>
using namespace std;
int a[100];
int main(){
int n;
cin>>n;
int m = 0;
int x;
//输入+去重
for(int i = 0; i < n; i ++ ){
cin>>x;
bool flag = false;
for(int j = 0; j < m; j ++){
if(a[j] == x){
flag = true;
break;
}
}
if(!flag) a[m ++] = x;
}
//选择排序
// for(int i = 0; i <= m - 2; i ++ ){
// int min_id = i;
// for(int j = i + 1; j < m; j ++ ){
// if(a[j] < a[min_id]) min_id = j;
// }
// swap(a[i],a[min_id]);
// }
sort(a, a + m);
cout<<m<<endl;
for(int i = 0; i < m; i ++ ){
cout<<a[i]<<" ";
}
return 0;
}
2.先排序后去重
对每个数都看它前面的数是否相同,如果相等,那么这个数就可以删掉
#include <iostream>
#include <algorithm>
using namespace std;
int a[100];
int main(){
int n;
cin>>n;
for(int i = 0; i < n; i ++ ){
cin>>a[i];
}
sort(a, a + n);
int m = 1;
for(int i = 1; i < n; i ++ ){
if(a[i]==a[i-1]) continue;
else{
a[m ++] = a[i];
}
}
cout<<m<<endl;
for(int i = 0; i < m; i ++ ){
cout<<a[i]<<" ";
}
return 0;
}