第五届蓝桥杯校内选拔赛

1>思维

输入一个字符串,求它包含多少个单词。单词间以一个或者多个空格分开。
第一个单词前,最后一个单词后也可能有0到多个空格。
比如:" abc xyz" 包含两个单词,"ab c xyz " 包含3个单词。

如下的程序解决了这个问题,请填写划线部分缺失的代码。

注意:只填写划线部分的代码,不要填写任何多余的内容。比如已经存在的小括号,注释或说明文字等。

int get_word_num(char* buf)
{
  int n = 0;
  int tag = 1;
  char* p = buf;

  for(;*p!=0 && *p!=13 && *p!=10;p++){
    if(*p==' ' && tag==0) tag=1;
    if( _____________________ ) { n++; tag=0; } //填空
  }

  return n;
}

int main()
{
  char buf[1000];
  fgets(buf,1000,stdin);
  printf("%d\n", get_word_num(buf));
  return 0;
}

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;

int get_word_num(char* buf)
{
	int n = 0;
	int tag = 1;
	char* p = buf;

	for (; *p != 0 && *p != 13 && *p != 10; p++) {//枚举
		if (*p == ' ' && tag == 0) tag = 1;	//如果是' '并且上一个不是' '
		if (tag == 1 && *p != ' ') { n++; tag = 0; }   //若果当前不是' '并且上一个是' '
	}

	return n;
}

int main()
{
	char buf[1000];
	fgets(buf, 1000, stdin);

	printf("%d\n", get_word_num(buf));
	return 0;
}

 

2>小数运算

1/1 + 1/2 + 1/3 + 1/4 + ... 在数学上称为调和级数。

它是发散的,也就是说,只要加上足够多的项,就可以得到任意大的数字。

但是,它发散的很慢:

前1项和达到 1.0
前4项和才超过 2.0
前83项的和才超过 5.0

那么,请你计算一下,要加多少项,才能使得和达到或超过 15.0 呢?

请填写这个整数。

注意:只需要填写一个整数,不要填写任何多余的内容。比如说明文字。

#include<iostream>
#include<algorithm>
using namespace std;
int main() {
	double cnt = 0;
	for (int i = 1; i < 10000000; i++) {
		cnt += 1.0 / (double)i;
		if (cnt >= 15.0) {
			cout << i << "\n";
			break;
		}
	}
	return 0;
}
//输出:1835421

 

3> 小数运算+四舍五入/小数二分

如果x的x次幂结果为10(参见【图1.png】),你能计算出x的近似值吗?

显然,这个值是介于2和3之间的一个数字。

请把x的值计算到小数后6位(四舍五入),并填写这个小数值。

注意:只填写一个小数,不要写任何多余的符号或说明。

 

【图1.png】:

方法一:小数二分

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;

void erf() {//方法一
	double le = 2.0, ri = 3.0, mid;
	for (int i = 1; i<200; i++)//小数二分搜索
		if (le< ri) {
			mid = (le + ri) / 2.0;
			if (pow(mid, mid) >= 9.99999999&&pow(mid, mid) <= 10.00000001)break;
			else if (pow(mid, mid) < 10.0)le = mid;
			else ri = mid;
		}
	printf("%.10f\n", mid);
}


int main() {
	erf();
	return 0;
}
// 结果:2.5061841458   答案保留六位即可

  方法二:枚举

#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;

void so()
{
	double x;
	for (x = 2.0; x<3.0; x += 0.00000001)//枚举
	{
		if (abs(pow(x, x) - 10.0)<0.000001)
			printf("%.10f\n", x);
	}
}

int main() {
	so();
	return 0;
}
// 结果:
//2.5061840969
//2.5061841069
//2.5061841169
//2.5061841269
//2.5061841369
//2.5061841469
//2.5061841569
//2.5061841669
//2.5061841769
//2.5061841869
//2.5061841969
//答案保留六位即可

 

4> dfs/全排列

今有7对数字:两个1,两个2,两个3,...两个7,把它们排成一行。
要求,两个1间有1个其它数字,两个2间有2个其它数字,以此类推,两个7之间有7个其它数字。如下就是一个符合要求的排列:

17126425374635

当然,如果把它倒过来,也是符合要求的。

请你找出另一种符合要求的排列法,并且这个排列法是以74开头的。

注意:只填写这个14位的整数,不能填写任何多余的内容,比如说明注释等。

方法一:dfs

#include<iostream>
#include<algorithm>
using namespace std;
int a[16], book[8];//a[i]代表第i个数 book[i]代表i是否用过
void dfs(int ans) {//ans代表当前第几个
	if (ans == 15) {
		for (int i = 1; i < 15; i++)
			cout << a[i];
		cout << "\n";
		return;
	}
	if (a[ans] != 0)dfs(ans + 1);
	for (int i = 1; i < 7; i++) {//依次枚举当前放数字几
		if (book[i] == 0 && a[ans] == 0 && a[ans + i + 1] == 0) {
			a[ans] = a[ans + i + 1] = i;//放入i
			book[i] = 1;//标记i已用

			dfs(ans + 1);

			book[i] = 0;
			a[ans] = a[ans + i + 1] = 0;
		}

	}
}
int main() {
	book[4] = 1;
	book[7] = 1;
	a[1] = a[9] = 7;
	a[2] = a[7] = 4;//搜索前一定要把标记的先标记上

	dfs(3);
	return 0;
}
//74151643752362

  方法二:全排列

#include<iostream>
#include<algorithm>
using namespace std;
 
void p() {//全排列方法   速度慢
    int b[15] = { 7,4,1,1,2,2,4,3,7,3,5,5,6,6 };//把数都导入
    bool book2[15];
    while (next_permutation(b + 2, b + 14)) {//全排列函数
        memset(book2, 0, sizeof(book2));
        int i;
        for (i = 0; i < 14; i++) {//枚举每个位置
            if (book2[i])continue;
            else {
                if (b[i] == b[i + b[i] + 1])
                    book2[i + b[i] + 1] = true;
                else break;
            }
        }
        if (i == 14) {//满足条件就输出
            for (i = 0; i < 14; i++)
                cout << b[i];
            cout << "\n";
            break;
        }
    }
}
int main() {
    p();
    return 0;
}
//74151643752362

  

5>思维

勾股定理,西方称为毕达哥拉斯定理,它所对应的三角形现在称为:直角三角形。

已知直角三角形的斜边是某个整数,并且要求另外两条边也必须是整数。

求满足这个条件的不同直角三角形的个数。

【数据格式】
输入一个整数 n (0<n<10000000) 表示直角三角形斜边的长度。
要求输出一个整数,表示满足条件的直角三角形个数。

例如,输入:
5
程序应该输出:
1

再例如,输入:
100
程序应该输出:
2

再例如,输入:
3
程序应该输出:
0


资源约定:
峰值内存消耗 < 256M
CPU消耗 < 1000ms

#include <iostream>
#include <algorithm>
#include<math.h>
using namespace std;
#define ll long long
ll a[100001];

int main()
{
	ll n,x,y,cnt = 0;
	cin >> n;
	for (int i = 1; i<n / sqrt(2); i++)//根据三角形构成条件,缩小范围
	{
		x = i*i;
		y = sqrt(n*n - x);
		if (x+y*y== n*n)cnt++;
	}
	cout << cnt << endl;
}

 

6>dfs

你一定听说过“数独”游戏。
玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个同色九宫内的数字均含1-9,不重复。

数独的答案都是唯一的,所以,多个解也称为无解。

本图的数字据说是芬兰数学家花了3个月的时间设计出来的较难的题目。但对会使用计算机编程的你来说,恐怕易如反掌了。

本题的要求就是输入数独题目,程序输出数独的唯一解。我们保证所有已知数据的格式都是合法的,并且题目有唯一的解。

格式要求,输入9行,每行9个数字,0代表未知,其它数字为已知。
输出9行,每行9个数字表示数独的解。

例如:
输入:
005300000
800000020
070010500
400005300
010070006
003200080
060500009
004000030
000009700

程序应该输出:
145327698
839654127
672918543
496185372
218473956
753296481
367542819
984761235
521839764

再例如,输入:
800000000
003600000
070090200
050007000
000045700
000100030
001000068
008500010
090000400

程序应该输出:
812753649
943682175
675491283
154237896
369845721
287169534
521974368
438526917
796318452

资源约定:
峰值内存消耗 < 256M
CPU消耗 < 2000ms

 

#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
char t[20][20];
//a:每个格的数  kx[][]:记录横向数是否已用  ky[][]:记录横向数是否已用  kj[][]:记录九宫格是否已用
int a[20][20], kx[20][20], ky[20][20],kj[20][20],ans=0;

void dfs(int x, int y) {
	//cout << "(" << x << "," << y << ")" << " ";
	if (ans)return;
	if (x == 10) {
		ans = 1;
		for (int i = 1; i < 10; i++) {
			for (int j = 1; j < 10; j++)
				cout << a[i][j];
			cout << "\n";
		}
		return;
	}
	if (a[x][y] == 0) {
		for (int i = 1; i<10; i++)
			if (kx[x][i] == 0 && ky[y][i] == 0&& kj[(x - 1) / 3 * 3 + (y + 2) / 3][i] ==0) {
				kj[(x - 1) / 3 * 3 + (y + 2) / 3][i] = 1;
				kx[x][i] = 1;
				ky[y][i] = 1;
				a[x][y] = i;

				if (y == 9)dfs(x + 1, 1);
				else dfs(x, y + 1);

				a[x][y] = 0;
				kx[x][i] = 0;
				ky[y][i] = 0;
				kj[(x - 1) / 3 * 3 + (y + 2) / 3][i] = 0;
			}
	}
	else {
		if (y == 9)dfs(x + 1, 1);
		else dfs(x, y + 1);
	}
	return;
}
int main() {
	for (int i = 1; i < 10; i++) {
		for (int j = 1; j < 10; j++) {
			cin >> t[i][j];
			a[i][j] = t[i][j] - '0';
			if (a[i][j] != 0) {
				kx[i][a[i][j]] = 1;
				ky[j][a[i][j]] = 1;
				kj[(i-1)/3*3+(j+2)/3][a[i][j]] = 1;//巧妙地是这里,将九大块刚好编号为1~9
			}
		}

	}
	cout << "\n";
	dfs(1, 1);
	return 0;
}

  

7:dp

 

  参考博文:https://blog.csdn.net/dodd9199/article/details/41916121

  这位博主说的很详细,Orz

 

G将军有一支训练有素的军队,这个军队除开G将军外,每名士兵都有一个直接上级(可能是其他士兵,也可能是G将军)。

现在G将军将接受一个特别的任务,需要派遣一部分士兵(至少一个)组成一个敢死队,为了增加敢死队队员的独立性,要求如果一名士兵在敢死队中,他的直接上级不能在敢死队中。
请问,G将军有多少种派出敢死队的方法。注意,G将军也可以作为一个士兵进入敢死队。
输入格式
输入的第一行包含一个整数n,表示包括G将军在内的军队的人数。军队的士兵从1至n编号,G将军编号为1。
接下来n-1个数,分别表示编号为2, 3, ..., n的士兵的直接上级编号,编号i的士兵的直接上级的编号小于i。
输出格式
输出一个整数,表示派出敢死队的方案数。由于数目可能很大,你只需要输出这个数除10007的余数即可。
样例输入1
3
1 1
样例输出1
4
样例说明
这四种方式分别是:
1. 选1;
2. 选2;
3. 选3;
4. 选2, 3。
样例输入2
7
1 1 2 2 3 3
样例输出2
40

数据规模与约定
对于20%的数据,n ≤ 20;
对于40%的数据,n ≤ 100;
对于100%的数据,1 ≤ n ≤ 100000。


资源约定:
峰值内存消耗 < 256M
CPU消耗 < 2000ms

#include <iostream>
#include<algorithm>
#include<vector>
using namespace std;
int n,dp[100010][2],t;
vector<int>v[100010];
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	cin >> n;
	for (int i = 2; i <= n; i++)
	{
		cin >> t;
		v[t].push_back(i);
	}
	for (int i = n; i > 0; i--) {    //从下向上
		dp[i][0] = 1;         //初始化
		dp[i][1] = 1;         //初始化
		for (int j = 0; j < v[i].size(); j++) {
			dp[i][0] *= (dp[v[i][j]][0] + dp[v[i][j]][1]);//下级(去+不去) 的累乘
			dp[i][1] *= dp[v[i][j]][0];//下级(不去)的累乘
			dp[i][0] %= 10007;
			dp[i][1] %= 10007;
		}
	}
	cout << dp[1][1] + dp[1][0] - 1 << "\n";//减去都不去的情况
	return 0;
}