第一题 一个串的子串是指该串的一个连续的局部。如果不要求连续,则可称为它的子序列。 比如对串: “abcdefg” 而言,“ab”,“abd”,“bdef” 等都是它的子序列。 特别地,一个串本身,以及空串也是它的子序列。
对两个串而言,可以有许多的共同的子序列,我们关心的是:它们所共同拥有的长度最大的子序列是多长。以下代码实现了这个问题的求解。请填写划线部分缺失的代码。
注意:只填写划线部分缺少的内容,不要填写任何多余的符号或注释、说明等。例如,不要填写已经给出的小括号。
inline max(int a, int b) { return a>b?a:b; } int f(char* x, char* y) { if(strlen(x)==0) return 0; if(strlen(y)==0) return 0; if(*x == *y) return f(x+1, y+1) + 1; return max(______________); } int main() { printf("%d\n", f("ac","abcd")); //2 printf("%d\n", f("acebbcde1133","xya33bc11de")); //5 return 0; }答案 : f(x, y + 1), f(x + 1, y)
第二题 历史上有许多计算圆周率pai的公式,其中,格雷戈里和莱布尼茨发现了下面的公式:
pai = 4*(1-1/3+1/5-1/7 …)
如图:
这个公式简单而优美,但美中不足,它收敛的太慢了。 如果我们四舍五入保留它的两位小数,那么:
累积了1项和是:4.00 累积了2项和是:2.67 累积了3项和是:3.47 。。。
请你写出它累积了100项的和是多少(四舍五入到小数后两位)。
注意:只填写该小数本身,不要填写任何多余的说明或解释文字。
答案:3.13
第三题 如果x的x次幂结果为10,你能计算出x的近似值吗?显然,这个值是介于2和3之间的一个数字。请把x的值计算到小数后6位(四舍五入),并填写这个小数值。
注意:只填写一个小数,不要写任何多余的符号或说明。
#include <iostream> #include <cstdio> #include <cmath> using namespace std; int main() { double x = 2; for(;x <= 3.0;x += 0.00000001) { if(fabs(pow(x,x) - 10) < 0.000001) printf("%.6lf\n",x); } return 0; }浮点数二分:
#include <iostream> #include <cstdio> #include <cmath> #define eps 1e-7 using namespace std; double f(double x) { return pow(x, x); } int main() { double l = 2.0, r = 3.0, mid; while(r - l > eps) { double mid = (l + r) / 2.0; if(f(mid) - 10 > eps ) r = mid; else l = mid; } cout << l; return 0; }第四题 今有7对数字:两个1,两个2,两个3,…两个7,把它们排成一行。 要求,两个1间有1个其它数字,两个2间有2个其它数字,以此类推,两个7之间有7个其它数字。如下就是一个符合要求的排列:
17126425374635
当然,如果把它倒过来,也是符合要求的。
请你找出另一种符合要求的排列法,并且这个排列法是以74开头的。
注意:只填写这个14位的整数,不能填写任何多余的内容,比如说明注释等。 思路分析: 1.这些数放到哪个位置上 2.这个位置可以放哪个数
枚举位置
#include<iostream> #include<string> using namespace std; int num[15] = {0,7,4,0,0,0,0,4,0,7,0,0,0,0,0}; int v[8] = {0}; void dfs(int pos) { if(num[pos]) dfs(pos + 1);//如果已经放,当前位置加一 if(pos == 15)//枚举结束 { for(int i = 1;i <= 14;i++) cout << num[i] << " "; return; } for(int i = 1;i <= 7;i++)//在未放数的位置尝试放1-7的数 { if(v[i]) continue;//该数已用过 int back = i + pos + 1;//对称的位置 if(pos > 14) continue;//不符合条件 if(num[pos] == 0 && num[back] == 0) { num[pos] = num[back] = i;//放数 v[i] = 1; dfs(pos + 1); v[i] = 0;//回溯 num[pos] = num[back] = 0; } } } int main() { v[4] = v[7] = 1; dfs(1);//对十四个位置进行枚举 return 0; }按照n=1~7进行DFS:我们每次尝试在当前存在的若干空位中放入n,如果可以放入,就往下搜索n+1;
#include<bits/stdc++.h> using namespace std; int num[15]={0,7,4,0,0,0,0,4,0,7,0,0,0,0,0}; void dfs(int n) { if(n==4) dfs(n+1);//4已经用过 if(n==7) { for(int i=1;i<=14;i++) printf("%d",num[i]); printf("\n"); return; } for(int i=1;i<=14;i++) { if(i==1 || i==2 || i==7 || i==9) continue; int bak=i+n+1; if(bak>14) continue; if(num[i]==0 && num[bak]==0) { num[i]=num[bak]=n; dfs(n+1); num[i]=num[bak]=0; } } } int main() { dfs(1); return 0; }第五题 勾股定理,西方称为毕达哥拉斯定理,它所对应的三角形现在称为:直角三角形。已知直角三角形的斜边是某个整数,并且要求另外两条边也必须是整数。求满足这个条件的不同直角三角形的个数。
【数据格式】
输入一个整数 n (0<n<10000000) 表示直角三角形斜边的长度。 要求输出一个整数,表示满足条件的直角三角形个数。
例如,输入:
5 程序应该输出:
1 再例如,输入:
100 程序应该输出:
2 再例如,输入:
3 程序应该输出:
0
#include<iostream> #include<string> using namespace std; int n,res; int main() { cin >> n; for(int a = 1; a <= n;a++) { for(int b = 1;b <= n;b++) { if(a + b >= n && a * a + b * b == n * n)//注意两边大于等于第三边 { cout << a << " " << b << " " << n << endl; res++; } } } cout << res / 2; return 0; }第六题 你一定听说过“数独”游戏。 如图,玩家需要根据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
思路:暴力枚举,尝试把1-9数放入每个坐标,检查大方格和小方格合法性
#include<iostream> #include<cstdio> using namespace std; const int n = 9; char g[n][n];//图 bool check(int x,int y,char ch)//检查是否合法 { for(int i = 0;i < 9;i++)//大方格当前行和列是否合法 { if(g[x][i] == ch || g[i][y] == ch)//该数已经出现过 return false; } int a = x / 3 * 3, b = y / 3 * 3;//转化成该带你所在的小方格起始地址 for (int i = a; i <= a + 2; i++) for (int j = b; j <= b + 2; j++) { if(g[i][j] == ch)//该数已经出现过 return false; } return true; } void dfs(int x,int y)//依次对每个位置进行枚举 { if(y == n)//列走到尽头 { x ++; y = 0; } if(x == n)//枚举结束 { for(int i = 0;i < n;i++) { for(int j = 0;j < n;j++) cout << g[i][j]; cout << endl; } exit(0); } if(g[x][y] - '0') dfs(x,y + 1);//该数已经枚举过 else { for(int i = 1;i <= 9;i++)//尝试把1-9放入 { if(check(x,y,i + '0'))//检查合法性 { g[x][y] = i + '0'; dfs(x,y + 1); g[x][y] = '0'; //回溯恢复现场 } } } } int main() { for(int i = 0;i < n;i++) for(int j = 0;j < n;j++) cin >> g[i][j]; dfs(0,0); return 0; }第七题 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;选2;选3;选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
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0 注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。 注意: 所有依赖的函数必须明确地在源文件中 #include , 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。
分析 这题是经典的树形DP问题,对于第 i 个士兵,它可以去也可以不去。我们定义:
f[i][1]:表示i士兵去;f[i][0]:表示i士兵不去。
那么状态转移就很简单了。如果i士兵不去,那么其直接下属可以去也可以不去;如果i士兵去,那么其直接下属一定不能去。即: f[i][0]=f[i][0]×∏(f[son][1]+f[son][0]) f[i][1]=f[i][1]×∏f[son][0] 注意:这里还需要排除G将军和士兵都不去的非法情况。
代码
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int N = 100010, mod = 10007; int n; int f[N][2]; int h[N], e[N], ne[N], idx; void add(int a, int b) { e[idx] = b, ne[idx] = h[a], h[a] = idx++; } void dfs(int u) { f[u][0] = f[u][1] = 1; for (int i = h[u]; ~i; i = ne[i]) { int j = e[i]; dfs(j); f[u][0] = (f[u][0] * (f[j][0] + f[j][1])) % mod; f[u][1] = f[u][1] * f[j][0] % mod; } } int main() { cin >> n; memset(h, -1, sizeof h); for (int i = 2; i <= n; i++) { int father; cin >> father; add(father, i); } dfs(1); cout << (f[1][0] + f[1][1] - 1) % mod << endl; return 0; }