2019肇庆学院“菜鸟杯“程序设计竞赛题解

A 解锁专家

阿炳是一个精通文理的小机灵鬼,它是一个解锁专家,也是一个诗人。一天,阿炳受邀前往黄台甫马哈那坤弃他哇劳狄希阿由他亚马哈底陆浦欧叻辣塔尼布黎隆乌冬帕拉查尼卫马哈洒坦,也就是今天俗称的曼谷,解一个被文字锁锁住的宝箱。
文字锁是这样描述的,
对于给定的一个n,问存在多少正整数x满足:

1、x>0;

2、x二进制位的位数不超过n,例如5=101(2),它的二进制位的位数就是3;

3、x的二进制形式,不存在连续的两个二进制位上的数都是1。例如 3=11(2),则不满足条件,但是5=101(2) 则满足条件。

阿炳思考了5分钟后,望着山下的美景,不禁写起了诗:

                        飞花两岸照船红,
                        波光山色两盈盈。
                        那年私语小窗边,
                        妾心陌上悠扬蝶。

原来阿炳不会解,为了掩饰尴尬,只好作诗缓解一些尴尬的气氛,阿炳作为一个知名解锁专家,当然是要面子的嘛,所以,阿炳请你帮帮他解决这个问题。
输入描述:

多测试数据样例,测试样例组数不超过10000;
每组数据一行,一个数n(1 ≤ n ≤ 100)。

输出描述:

每组数据输出一个数,满足条件的正整数x的个数取模433494437(即答案需要%433494437)

解题思想

把情况列出来后,发现是斐波那契数列,然后加上前缀和就能计算n之前的数量。

#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define IOS ios::sync_with_stdio(false)
#define FRE freopen("1.txt", "r", stdin)
#define MAXN 1005
ll _ans[MAXN], ans[MAXN];
void fun(int x) {
	_ans[1] = _ans[2] = 1;
	for (int i = 3; i < x; i++) {
		_ans[i] = _ans[i - 1] + _ans[i - 2];
        _ans[i] %= 433494437;
	}
	ans[1] = 1;
	for (int i = 2; i < x; i++) {
		ans[i] = ans[i - 1] + _ans[i];
	}
	for (int i = 1; i < x; i++) ans[i] %= 433494437;
}
int main(int argc, char** argv) {
	IOS;
	fun(200);
	int n;
	while (cin >> n) {
		cout << ans[n] << endl;
	}
	return 0;
}

F 参赛

jx队长半夜@小胖:你快出一道签到题呀,简单点的,不行打你啊。小胖吓得赶紧下床想题,边想边和jx队长吹水,想起了参加acm的种种经历。有感而发和jx队长说了想法之后,jx队长:你这什么题意,不行啊太难了,我来改。一顿争辩之后小胖折服了,内心:jx队长牛逼。jx队长:睡吧睡吧,找时间请你喝奶茶。

众所周知:icpc赛制中,一支队伍由三个队员和一个教练组成,一个教练可以兼任多个队伍的教练;天梯赛赛制中,一支队伍由十个队员组队和一个教练组成,一个教练可以兼任多个队伍的教练;同时,一个队员可以同时参与两种比赛,但不能同时参与同一比赛的不同队伍。
如果参赛队的Q群里教练和队员的人数共有n人,参赛队是否刚好所有人都能同时组成队伍参赛?

输入描述:

多测试用例
每组测试用例一行,包括一个整数n(1≤n≤300),表示群内的人数有n人

输出描述:

对于每组测试用例
如果所有人都能同时参加两种比赛,请输出All;
如果所有人都能同时参加icpc但不能同时参加天梯赛,请输出First;
如果所有人都能同时参加天梯赛不能同时参加icpc,请输出Second;
否则请输出No。

解题思想

签到题。教练一定要存在,所以余数为零的时候要减掉一只队伍。同时教练数量不能大于队伍数量。

#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define IOS ios::sync_with_stdio(false)
#define FRE freopen("1.txt", "r", stdin)
#define MAXN 100005
int main(int argc, char** argv) {
	IOS;
	int n;
	bool fir, sec;
	while (cin >> n) {
		fir = false, sec = false;
		int _icpc = n % 3, icpc = n / 3;
		if (_icpc == 0) {
			icpc--;
			_icpc += 3;
		}
		if (icpc && _icpc && _icpc <= icpc) fir = true;

		int _noi = n % 10, noi = n / 10;
		if (_noi == 0) {
			noi--;
			_noi += 10;
		}
		if (noi && _noi && _noi <= noi) sec = true;

		if (fir && sec) cout << "All" << endl;
		else if (fir) cout << "First" << endl;
		else if (sec) cout << "Second" << endl;
		else cout << "No" << endl;
	}
	return 0;
}

G 数数有多少水坑

题目描述

有一个由26个小写字母构成的n*m的矩阵(1≤n,m≤1000)。上下左右四连通的区域内有 ‘j’,‘e’,‘s’,‘i’ 这四个小写字母就属于同一个水坑,其余字母则代表地面。 请问该矩阵内有多少个水坑?
输入描述:

多组测试用例,保证 ∑(n*m)≤107;
每组测试第一行输入两个整数,分别为行数n和列数m;

接下来n行每行输入m个字符(字符只包含小写字母)。

输出描述:

输出水坑的总个数

解题思路

一开始以为很难,要上下左右得找。后面一想,上下左右的找,那广搜深搜都能写的啊。就开始搜索。后面wa了两次段错误发现是自己的check()出问题了。
我的check()一开始是这么写的

  //错误写法。
if(x < 0 && x >= n) return false;
  //而正确的应该是这么写。
if(x < 0 || x >= n) return false;

最后修改好后提交ac。

#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define IOS ios::sync_with_stdio(false)
#define FRE freopen("1.txt", "r", stdin)
#define MAXN 10005
int re[MAXN][MAXN], n, m;
char book[4] = { 'j', 'e', 's', 'i' };
bool ma[MAXN][MAXN];
struct node {
	int x;
	int y;
}Next[4];
bool check(int x, int y) {
	if (x < 0 || x >= n) return false;
	if (y < 0 || y >= m) return false;
	return true;
}
void bfs(int x, int y);
void dfs(int x, int y);
bool check(int x, int y){
	if(x < 0 || x >= n) return false;
    if(y < 0 || y >= m) return false;
    return true;
}
void init() {
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			ma[i][j] = false;
		}
	}
}
int main(int argc, char** argv) {
	IOS;
	Next[0].x = 1; Next[0].y = 0;
	Next[1].x = -1; Next[1].y = 0;
	Next[2].x = 0; Next[2].y = 1;
	Next[3].x = 0; Next[3].y = -1;
	string str;
	while (cin >> n >> m) {
		init();
		for (int i = 0; i < n; i++) {
			cin >> str;
			bool flag;
			for (int j = 0; j < m; j++) {
				flag = false;
				for (int k = 0; k < 4; k++) if (str[j] == book[k]) { flag = true; break; }
				if (flag) re[i][j] = 1;
				else re[i][j] = 0;
			}
		}
		/// re == 1是水坑 re==0 是平地
		int ans = 0;
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				if (!ma[i][j] && re[i][j] == 1) {
					ans++;
					ma[i][j] = true;
					//将这个水坑扩大标记
					bfs(i, j);
				}
			}
		}
		cout << ans << endl;
	}
	return 0;
}



void bfs(int x, int y) {
	node S, T; S.x = x; S.y = y;
	queue<node>now;
	now.push(S);
	while (!now.empty()) {
		T = now.front();
		now.pop();
		for (int k = 0; k < 4; k++) {
			T.x += Next[k].x;
			T.y += Next[k].y;
			if (!ma[T.x][T.y] && check(T.x, T.y) && re[T.x][T.y] == 1) { now.push(T); }
			ma[T.x][T.y] = true;
			T.x -= Next[k].x;
			T.y -= Next[k].y;
		}
	}
}

void dfs(int x, int y) {
	node T; T.x = x, T.y = y;
	ma[x][y] = true;
	for (int i = 0; i < 4; i++) {
		T.x += Next[i].x;
		T.y += Next[i].y;
		if (check(T.x, T.y) && !ma[T.x][T.y] && re[T.x][T.y] == 1) dfs(T.x, T.y);
		T.x -= Next[i].x;
		T.y -= Next[i].y;
	}
}

H 你相信爱情吗?

题目描述

牛郎与织女的故事想必大家都耳熟能详吧,织女真的太爱牛郎了,为了和牛郎在一起,不惜下凡与天庭作对,最后他们俩个还是被硬生生的分离开。织女有一天突然想,要是牛郎不爱她了她得怎么办,由此,织女想考验一下牛郎到底爱不爱她。考验如下:一开始,牛郎和织女在同一个星球上的同一个位置n上,这颗星球上的钻石均匀连续分布在这一星球赤道上;赤道上分布了n个位置,编号为连续的1~n,其中每个位置都放置有一个钻石,总共n个钻石。织女给牛郎一些条件考验限制:

1、牛郎每次只能顺时针移动m步(n往1的方向移动就是顺时针)。

2、牛郎与织女相见后把收集到的钻石给织女。

3、织女要拿到n个钻石。

NOTE:牛郎和织女一开始都在n的位置,织女会一直在n位置等牛郎,牛郎每次结束移动时到达新的位置,都会把这个位置的钻石收集起来,而中间经过的位置不能收集。
牛郎是个执着的人,他会一直走到取完n个钻石,如果永远取不完就输出-1。问:牛郎能不能完成考验?
输入描述:

第一行一个整数t代表有t个测试样例(1≤t≤100000)
接下来t行,每行俩个整数n和m,如题面所示,1≤n,m<1e18,m≤n;

输出描述:

牛郎若能完成考验就输出最小移动次数,不能就输出-1。

解题思路

当然相信爱情了呀哈哈哈。
咳咳。
这道题是我最后十分钟才看的题。太可惜了。
找规律。只要gcd(a, b) != 1,那么就永远拿不完所有的钻石。

#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define IOS ios::sync_with_stdio(false)
#define FRE freopen("1.txt", "r", stdin)
const ll MAXN = 1e9;
ll gcd(ll a, ll b){
    return b == 0 ? a : gcd(b, a%b);
}
int main(int argc, char** argv) {
	IOS;
	int t; cin >> t;
	ll m, n;
	while (t--) {
		cin >> n >> m;
        if(gcd(m, n) == 1) cout << n << endl;
        else cout << -1 << endl;
	}
	return 0;
}

J 试试划水

题目描述

师兄猜你看的第一道题是这道哈哈哈。没错,师兄给你送福利了,这道题你只需要呆萌呆萌的把下面的代码交上去就行了,师兄是好人【坏笑】。

#include<bits/stdc++.h>
char ch[100000+5];
int main(){    
    int t;
    scanf("%d",&t);
    while(t--) { 
        int len,ans=0;    
        scanf("%s",ch);  
        len=strlen(ch);
        for(int i=0;i<len;i++)
           for(int j=i+1;j<len;j++)
               for(int k=j+1;k<len;k++)    
                  if(ch[i]=='Z'&&ch[j]=='Q'&&ch[k]=='U')        
                      ans++;  
         printf("%d\n",ans);
    }
    return 0;
} 

输入描述:

第一行一个整数t代表有t组测试用例,0≤t≤100。

接下来t行,输入一个仅包含’Z’,'Q’和’U’三种字符的字符串s。( 0<|s|≤100000,|s|为字符串s的长度)

输出描述:

每行一个整数表示代码中ans的值。

解题思路

不会吧不会吧不会吧不会真的有人把学长的代码往上交吧!

咳咳。这道题也是找规律的一道题。就比如"ZZZQQUQUU"的串,我只需要找到一个Q前面的Z的数量,再找这个Q后面U的数量即可。也就是我第一个Q的答案是3X3, 第二个Q的答案是3X3,第三个Q的答案是3X2, 那么我就输出9+9+6即可。

注意:只能是一重循环,否则1e6的大小会超时。

#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define IOS ios::sync_with_stdio(false)
#define FRE freopen("1.txt", "r", stdin)
#define MAXN 100005
int re[MAXN];
struct node {
	int num;
	int howz, howu;
}Z, Q[MAXN], U;
void init(int len) {
	for (int i = 0; i < len; i++) {
		Q[i].num = 0;
		Q[i].howz = 0;
		Q[i].howu = 0;
	}
}
int main(int argc, char** argv) {
	IOS;
	int n; cin >> n;
	while (n--) {
		Z.num = U.num = 0;
		string str; cin >> str;
		ll len = str.length(), ans = 0;
		for (int i = 0; i < len; i++) {
			if (str[i] == 'Z') { Z.num++; }
			else if (str[i] == 'Q') { Q[i].num++; Q[i].howz = Z.num; }
		}
		for (int i = len - 1; i >= 0; i--) {
			if (str[i] == 'U') U.num++;
			else if (str[i] == 'Q') { Q[i].howu = U.num; ans += Q[i].howu * Q[i].howz; }
		}
		cout << ans << endl;
		init(len);
	}
	return 0;
}

K 钟Sir的任务

题目描述

钟Sir最近迷上一种排列交换游戏,游戏规则是这样的:
由1n的n个互不相同的整数,按任意顺序组成的一个序列,称为1n的一个排列。(如:[1,3,2]是一个排列,但[1,2,2][1,3,4]不是一个排列)
对于给定的排列,每次操作可以交换位置i和i+1上的元素(1≤i<n,显然一共存在n-1种操作),但每种操作最多执行一次,操作次序不限(显然最多执行n-1次操作,当然也可以选择不操作)。

问在不违反游戏规则的前提下,能够得到的字典序最小的排列是什么?(如:[1,2,3]字典序小于[1,3,2])

钟Sir觉得一定要玩t场游戏,才能够体现他的强悍实力,但是钟Sir是人不是神仙来的,没办法一口气玩t场游戏(还会死很多脑细胞的),所以钟Sir想让你写一个程序来帮助他。

输入描述:

第一行是一个整数t(1<=t<=100),表示游戏场数。

接下来对每场游戏有两行描述,

第一行是一个整数n(1<=n<=100),表示排列的长度,

第二行包含n个整数,表示给定的1~n的一个排列。

输出描述:

输出在不违反游戏规则的前提下,能够得到的字典序最小的排列。

解题思路

这道题其实没有太懂,主要是想到了我在后面的小的数往前拉,从后往前遍历就可。遍历到没有得交换即可。而且要记住每个位点只能交换一次。

#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define IOS ios::sync_with_stdio(false)
#define FRE freopen("1.txt", "r", stdin)
#define MAXN 1005
int re[MAXN], _re[MAXN];
bool book[MAXN];
void Swap(int& a, int& b) {
	int _a = a;
	a = b;
	b = _a;
}
int main(int argc, char** argv) {
	IOS;
	int t; cin >> t;
	while (t--) {
		int n, ans = 0; cin >> n;
		memset(book, 0, sizeof(book));
		for (int i = 0; i < n; i++) { cin >> re[i]; _re[i] = re[i]; }
		bool flag = false;
        int len = n;
        while(len--){
            for (int i = n - 1; i >= 0; i--) {
                if (!book[i] && re[i] < re[i - 1]) {
                    Swap(re[i], re[i - 1]);
                    book[i] = true;
                }
            }
        }
		for (int i = 0; i < n; i++) cout << re[i] << (i == n - 1 ? '\n' : ' ');
	}
	return 0;
}

L JAJA_Xin的小心思

题目描述

快放寒假了,虽然时间还早,但JAJA_Xin已经准备着回家了。他只有一个行李箱,行李箱的容积为m。但是他的行李又很多,所以他去网购了n个压缩袋,并把他的行李分装成了n个袋子,第i个装好的袋子有初始体积ai,压缩后的体积为bi,但JAJA_Xin比较懒,他希望能尽量少压缩几个袋子就把所有行李装进行李箱,现已知所有的ai和bi,他至少要压缩几个袋子才能把行李装进行李箱?

一顿sao操作之后,他算好了要压缩几个袋子,jx队长从背后拍了一下他的肩:“怎么,想溜了?乖乖留下集训吧!”

输入描述:

多测试用例,保证 ∑n≤107;
每组用例的第一行包含两个整数n和m(1≤n≤105,1≤m≤109)。
接下来输入有n行,第i行有两个整数ai和bi(1≤ai,bi≤109, bi<ai)。

输出描述:

请输出需要压缩几个袋子。
如果无法装进行李箱,请输出-1。

解题思路

一顿操作之后发现,原来是贪心,那贪就完了。直接把未压缩的空间全部加起来,然后减去压缩空间最大的,如果装不下,继续压缩第二个减去第二大的空间。到了怎么找的问题了,很简单,就是结构体排序。

#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define IOS ios::sync_with_stdio(false)
#define FRE freopen("1.txt", "r", stdin)
#define MAXN 10000005
struct node {
	ll mae, ato;
	ll val;
}re[MAXN];
bool cmp(node a, node b) {
    if(a.val ==  b.val) return a.ato < b.ato;
	return a.val > b.val;
}
int main(int argc, char** argv) {
	IOS;
	int n, m;
	while (cin >> n >> m) {
		ll ans = 0, now = 0, can = 0;
		for (int i = 0; i < n; i++) { 
			cin >> re[i].mae >> re[i].ato; 
			re[i].val = re[i].mae - re[i].ato; 
			now += re[i].mae; 
			can += re[i].ato; 
		}
		if (can > m) { cout << -1 << endl; continue; }
		else if (now <= m) { cout << 0 << endl; continue; }
		sort(re, re+n, cmp);
		for (int i = 0; i < n; i++) {
			now -= re[i].val;
			ans++;
			if (now <= m) break;
		}
		cout << ans << endl;
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Raoxiaomi.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值