目录
1、网友年龄
题意
某君新认识一网友。当问及年龄时,他的网友说:“我的年龄是个2位数,我比儿子大27岁,如果把我的年龄的两位数字交换位置,刚好就是我儿子的年龄”。请你计算:网友的年龄一共有多少种可能情况?提示:30岁就是其中一种可能哦。请填写表示可能情况的种数。注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
思路
枚举
C++代码
#include<iostream>
using namespace std;
int main()
{
int ans=0;//答案
for(int i=27;i<100;i++)//枚举父亲的年龄
{
int j=i,t=0;//t存放i的两位数交换后的数
while(j)
{
t=t*10+j%10;
j/=10;
}
if(i-t==27) ans++;//满足条件就加一
}
printf("%d\n",ans);
return 0;
}
答案
7
2、生日蜡烛
题意
某君从某年开始每年都举办一次生日party,并且每次都要吹熄与年龄相同根数的蜡烛。现在算起来,他一共吹熄了236根蜡烛。请问,他从多少岁开始过生日party的?请填写他开始过生日party的年龄数。注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
思路
枚举,考虑普通的情况,即每年都过一次生日,设开始过生日时的年龄为a1,经过n年的生日后吹熄了236根蜡烛,则由公差为1的等差数列求和公式得a1=(472-n(n-1))/(2n),因为a1和n是整数,因此可以通过枚举n的值来求a1。
C++代码
#include<iostream>
using namespace std;
int main()
{
for(int i=3;i<=100;i++)//i表示举办了i年Party
{
int temp=472-i*(i-1);
if(temp<0) break;
int temp2=2*i;
if(temp%temp2==0) printf("%d\n",temp/temp2);
}
return 0;
}
答案
26
3、方格填数
题意
如下的10个格子。填入0~9的数字。要求:连续的两个数字不能相邻(左右、上下、对角都算相邻)。一共有多少种可能的填数方案?请填写表示方案数目的整数。注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
思路
DFS
C++代码
#include<iostream>
#include<cmath>
using namespace std;
int a[5][6];//在3X4的数组周围填充一圈,这样方便判断
int d[8][2]={{-1,-1},{0,-1},{1,-1},{-1,0},{1,0},{-1,1},{0,1},{1,1}};//八个方向
int ans=0;//结果
bool vis[10];//vis[i]=true表示数字i已经被使用
void dfs(int i,int j)//考虑a[i][j]可以填的数
{
for(int k=0;k<10;k++)//遍历0~9
if(!vis[k])
{
//如果数字k还没有使用,就考虑此处是否能填k
bool flag=true;
for(int t=0;t<8;t++)//如果a[i][j]=k,考虑是否和它的八个方向的元素是否相差为1
{
int x=i+d[t][0];
int y=j+d[t][1];
if(abs(k-a[x][y])==1)
{
flag=false;//记录此处不能填k
break;
}
}
if(flag)//如果此处能填数字k,就考虑填数字k
{
if(i==3&&j==3)//如果是最后一个元素,则结果加一
{
ans++;
return;
}
int nextj=j+1,nexti=i;//此处填了k,现在要填下一个位置了
if(nextj>4)//如果nextj>4说明第i行已经填完,开始填下一行
{
nextj-=4;
nexti++;
}
a[i][j]=k;//记录此处填数字k
vis[k]=true;//标记数字k已经被使用了
dfs(nexti,nextj);
a[i][j]=-10;//如果此处不填k,考虑其他可能,就将vis[k]置为false
vis[k]=false;
}
}
}
int main()
{
for(int i=0;i<5;i++)
for(int j=0;j<6;j++)
a[i][j]=-10;//将数组a[][]各个元素初始化为-10
dfs(1,2);//从(1,2)处开始深搜
printf("%d\n",ans);
return 0;
}
答案
1580
4、快速排序
题目
排序在各种场合经常被用到。快速排序是十分常用的高效率的算法。其思想是:先选一个“标尺”,用它把整个队列过一遍筛子,
以保证:其左边的元素都不大于它,其右边的元素都不小于它。这样,排序问题就被分割为两个子区间。再分别对子区间排序就可以了。下面的代码是一种实现,请分析并填写划线部分缺少的代码。
#include <stdio.h>
void swap(int a[], int i, int j)
{
int t = a[i];
a[i] = a[j];
a[j] = t;
}
int partition(int a[], int p, int r)
{
int i = p;
int j = r + 1;
int x = a[p];
while(1){
while(i<r && a[++i]<x);
while(a[--j]>x);
if(i>=j) break;
swap(a,i,j);
}
______________________;
return j;
}
void quicksort(int a[], int p, int r)
{
if(p<r){
int q = partition(a,p,r);
quicksort(a,p,q-1);
quicksort(a,q+1,r);
}
}
int main()
{
int i;
int a[] = {5,13,6,24,2,8,19,27,6,12,1,17};
int N = 12;
quicksort(a, 0, N-1);
for(i=0; i<N; i++) printf("%d ", a[i]);
printf("\n");
return 0;
}
注意:只填写缺少的内容,不要书写任何题面已有代码或说明性文字。
思路
排序
答案
swap(a,p,j)
5、消除尾一
题意
下面的代码把一个整数的二进制表示的最右边的连续的1全部变成0。如果最后一位是0,则原数字保持不变。如果采用代码中的测试数据,应该输出:
00000000000000000000000001100111 00000000000000000000000001100000
00000000000000000000000000001100 00000000000000000000000000001100
请仔细阅读程序,填写划线部分缺少的代码。
#include <stdio.h>
void f(int x)
{
int i;
for(i=0; i<32; i++) printf("%d", (x>>(31-i))&1);
printf(" ");
x = _______________________;
for(i=0; i<32; i++) printf("%d", (x>>(31-i))&1);
printf("\n");
}
int main()
{
f(103);
f(12);
return 0;
}
注意:只填写缺少的内容,不要书写任何题面已有代码或说明性文字。
思路
位运算,消除x的末尾连续的1可以用x=x&(x+1)实现
答案
x&(x+1)
6、寒假作业
题意
现在小学的数学题目也不是那么好玩的。看看这个寒假作业:
每个方块代表1~13中的某一个数字,但不能重复。
比如:
6 + 7 = 13
9 - 8 = 1
3 * 4 = 12
10 / 2 = 5
以及:
7 + 6 = 13
9 - 8 = 1
3 * 4 = 12
10 / 2 = 5
就算两种解法。(加法,乘法交换律后算不同的方案)你一共找到了多少种方案?
请填写表示方案数目的整数。注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
思路
DFS
C++程序
#include<iostream>
using namespace std;
bool vis[14];//vis[i]=false表示数字i还没被使用
int a[13];//记录这十二个数
int ans=0;//统计种类数
bool cal(int k,int i)//如果k是3的倍数,那么就判断第k个数为i是否符合
{
if(k==3)
return a[k-2]+a[k-1]==i;//是否满足加法
else if(k==6)
return a[k-2]-a[k-1]==i;//是否满足减法
else if(k==9)
return a[k-2]*a[k-1]==i;//是否满足乘法
else
return a[k-2]==a[k-1]*i;//是否满足除法
}
void dfs(int k)
{
if(k==13)//已经填了12个数,结果加一,并返回
{
ans++;
return;
}
for(int i=1;i<=13;i++)//遍历13个数
{
if(!vis[i])//如果数字i还没有被使用,就考虑让a[k]=i
{
if(k%3!=0||cal(k,i))//如果k不是3的倍数,或者如果是3的倍数但是满足等式
{
a[k]=i;//让a[k]=i;
vis[i]=true;//数字i被使用
dfs(k+1);//填下一个数字
vis[i]=false;//考虑a[k]填其他数字
}
}
}
}
int main()
{
dfs(1);
printf("%d\n",ans);
return 0;
}
答案
64
7、剪邮票
题意
如图1, 有12张连在一起的12生肖的邮票。现在你要从中剪下5张来,要求必须是连着的。(仅仅连接一个角不算相连)。比如,图2,图3中,粉红色所示部分就是合格的剪取。请你计算,一共有多少种不同的剪取方法。
图1
图2
图3
请填写表示方案数目的整数。注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
思路
使用DFS选择五个位置,然后再通过另一个DFS判断这五个位置是否连接在一起。
C++程序
#include<iostream>
#include<cstring>
using namespace std;
bool vis[3][4];
bool temp[3][4];
int d[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
int ans;
void dfs2(int x,int y)
{
temp[x][y]=false;
for(int i=0;i<4;i++)
{
int fx=x+d[i][0];
int fy=y+d[i][1];
if(0<=fx&&fx<3&&0<=fy&&fy<4&&temp[fx][fy])
dfs2(fx,fy);
}
}
//在标号大于等于start的位置中选择一个位置作为第k个被裁剪的位置
void dfs1(int k,int start)
{
if(k==6)//已经挑选了五个位置了
{
//判断这五个位置是否连接在一起
for(int i=0;i<3;i++)
for(int j=0;j<4;j++)
temp[i][j]=vis[i][j];
int cnt=0;//发现裁剪的位置的次数
for(int i=0;i<3;i++)
for(int j=0;j<4;j++)
{
if(temp[i][j])//(i,j)是被裁剪的位置
{
dfs2(i,j);
cnt++;
}
}
if(cnt==1) ans++;//cnt=1表示五个位置连接在一起,结果加一
return;
}
/*
在区间[start,7+k)中选择一个位置作为第k个被裁剪的位置
第k个位置的标号要小于7+k,因为共12个标号(0..11),
第k个位置选择后还差5-k个位置没选择,所以第k个位置的选择的标号
要小于7+k
*/
for(int i=start;i<7+k;i++)
{
int x=i/4;
int y=i%4;
vis[x][y]=true;//考虑第k个位置为(x,y)
//在标号大于等于i+1的位置中选择一个位置作为第k+1个被裁剪的位置
dfs1(k+1,i+1);
vis[x][y]=false;//考虑下一个位置为第k个被裁剪的位置
}
}
int main()
{
ans=0;
dfs1(1,0);
printf("%d\n",ans);
return 0;
}
答案
116
8、四平方和
题意
四平方和定理,又称为拉格朗日定理:每个正整数都可以表示为至多4个正整数的平方和。如果把0包括进去,就正好可以表示为4个数的平方和。
比如:
5 = 0^2 + 0^2 + 1^2 + 2^2
7 = 1^2 + 1^2 + 1^2 + 2^2
(^符号表示乘方的意思)
对于一个给定的正整数,可能存在多种平方和的表示法。
要求你对4个数排序:
0 <= a <= b <= c <= d
并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法
程序输入为一个正整数N (N<5000000)
要求输出4个非负整数,按从小到大排序,中间用空格分开
例如,输入:
5
则程序应该输出:
0 0 1 2
再例如,输入:
12
则程序应该输出:
0 2 2 2
再例如,输入:
773535
则程序应该输出:
1 1 267 838
资源约定:
峰值内存消耗 < 256M
CPU消耗 < 3000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。
思路
暴力枚举
C++程序
#include<iostream>
#include<cmath>
using namespace std;
int main()
{
int n;
scanf("%d",&n);
int len=sqrt(n);
for(int i=0;i<=len;i++)
for(int j=i;j<=len;j++)
for(int k=j;k<=len;k++)
{
int t=n-i*i-j*j-k*k;
int temp=sqrt(t);
if(temp*temp==t&&temp>=k)
{
printf("%d %d %d %d\n",i,j,k,temp);
return 0;
}
}
return 0;
}
9、密码脱落
题意
X星球的考古学家发现了一批古代留下来的密码。
这些密码是由A、B、C、D 四种植物的种子串成的序列。
仔细分析发现,这些密码串当初应该是前后对称的(也就是我们说的镜像串)。
由于年代久远,其中许多种子脱落了,因而可能会失去镜像的特征。
你的任务是:
给定一个现在看到的密码串,计算一下从当初的状态,它要至少脱落多少个种子,才可能会变成现在的样子。
输入一行,表示现在看到的密码串(长度不大于1000)
要求输出一个正整数,表示至少脱落了多少个种子。
例如,输入:
ABCBA
则程序应该输出:
0
再例如,输入:
ABDCDCBABC
则程序应该输出:
3
资源约定:
峰值内存消耗 < 256M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。
思路
最长公共子序列,LCS。题目可以这样来思考,添加最少的字符使得字符串变成回文字符串,因此我们可以求出它和它的逆串的最长公共子序列的长度,那么至少需要添加的字符数为它的长度-LCS(因为不同的数只有长度-LCS个,因此在对应的位置添加对应的字符即可)
C++程序
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
const int N=1005;
int dp[N][N];
//最长公共子序列
int LCS(string a,string b)
{
for(int i=0;i<=a.length();i++)
for(int j=0;j<=a.length();j++)
{
if(i==0||j==0)
dp[i][j]=0;
else if(a[i]==b[j])
dp[i][j]=dp[i-1][j-1]+1;
else
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}
return dp[a.length()][b.length()];
}
int main()
{
string a,b;
cin>>a;
b=a;
reverse(b.begin(),b.end());
cout<<a.length()-LCS(a,b)<<endl;
return 0;
}
10、最大比例
题意
X星球的某个大奖赛设了M级奖励。每个级别的奖金是一个正整数。
并且,相邻的两个级别间的比例是个固定值。
也就是说:所有级别的奖金数构成了一个等比数列。比如:
16,24,36,54
其等比值为:3/2
现在,我们随机调查了一些获奖者的奖金数。
请你据此推算可能的最大的等比值。
输入格式:
第一行为数字 N (0<N<100),表示接下的一行包含N个正整数
第二行N个正整数Xi(Xi<1 000 000 000 000),用空格分开。每个整数表示调查到的某人的奖金数额
要求输出:
一个形如A/B的分数,要求A、B互质。表示可能的最大比例系数
测试数据保证了输入格式正确,并且最大比例是存在的。
例如,输入:
3
1250 200 32
程序应该输出:
25/4
再例如,输入:
4
3125 32 32 200
程序应该输出:
5/2
再例如,输入:
3
549755813888 524288 2
程序应该输出:
4/1
资源约定:
峰值内存消耗 < 256M
CPU消耗 < 3000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。
思路
辗转相减。
对a1=q^x1、a2=q^x2、a3=q^x3、a4=q^x4、a5=q^x5、a6=q^x6、...
已知a1、a2、a3、a4、a5、a6、...的值,不知道q和x1、x2、x3、x4、x5、x6、...的值
求最大公比使得a1,a2,a3,a4,a5,a6,...是某个等比数列的某几项(不一定是连续的几项
这里的下标不代表它们在等比数列中的位置)
易得所求的公比是 q^x,其中x=是x1,x2,x3,x4,x5,x6,...的约数
这样任何一个数都能由q^x乘若干个q^x的得到,因此上面的数一定是等比数列的某一项
显然,当x是x1,x2,x3,x4,x5,x6,...的最大公约数时q^x达到最大
求法:
定义Q(a,b)是由a,b唯一确定的最大比例,
那么Q(a,b)=Q(q^x,q^y)=Q(q^x,q^(x-y))=Q(a,b/a) a<b
只需要重复这个“辗转相减法”就可以得到最后的答案。
C++程序
版本一
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=105;
ll gcd(ll n,ll m)
{
return m==0?n:gcd(m,n%m);
}
//分数
struct F{
ll up,dw;
F(){}
F(ll a,ll b)// a/b
{
ll g=gcd(a,b);
up=a/g;
dw=b/g;
}
bool operator <(const F &fa)const// a/b<c/d 等价于 a*d<b*c
{
return up*fa.dw<dw*fa.up;
}
bool operator ==(ll x)const
{
return up==x*dw;
}
F operator /(const F &fa)
{
return F(up*fa.dw,dw*fa.up);
}
}f[N];
/*
对a1=q^x1、a2=q^x2、a3=q^x3、a4=q^x4、a5=q^x5、a6=q^x6、...
已知a1、a2、a3、a4、a5、a6、...的值,不知道q和x1、x2、x3、x4、x5、x6、...的值
求最大公比使得a1,a2,a3,a4,a5,a6,...是某个等比数列的某几项(不一定是连续的几项
这里的下标不代表它们在等比数列中的位置)
易得所求的最大公比是 q^x,其中x=gcd(x1,x2,x3,x4,x5,x6,...)
这样任何一个数都能由ans乘若干个q的得到,因此上面的数一定是等比数列的某一项
,而且这样最大
求法:
定义Q(a,b)是由a,b唯一确定的最大比例,
那么Q(a,b)=Q(q^x,q^y)=Q(q^x,q^(x-y))=Q(a,b/a) a<b
只需要重复这个“辗转相减法”就可以得到最后的答案。
*/
F qgcd(F n,F m)
{
if(n<m) swap(n,m);
if(m==1)
return n;
else
return qgcd(n/m,m);
}
int main()
{
ll a[N];
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%lld",&a[i]);
sort(a,a+n);//排序
n=unique(a,a+n)-a;//去重
for(int i=1;i<n;i++)
{
f[i]=F(a[i],a[i-1]);
}
for(int i=2;i<n;i++)
f[1]=qgcd(f[1],f[i]);
printf("%lld/%lld\n",f[1].up,f[1].dw);
return 0;
}
版本2:参见
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=105;
//求最大公约数
ll gcd(ll n,ll m)
{
return m==0?n:gcd(m,n%m);
}
/*
n=q^i m=q^j 求q^x 其中x=gcd(i,j)
设 qgcd(q^i,q^j)=q^(gcd(i,j)) *1*
由辗转相减求最大公约数可知,gcd(i,j)=gcd(i-j,j) i>j *2*
由1、2式可得
qgcd(n,m)=qgcd(q^i,q^j)=q^(gcd(i,j))=q^(gcd(i-j,j))=qgcd(q^(i-j),q^j)=qgcd(n/m,m)
即 qgcd(n,m)=qgcd(n/m,m)
当min(n/m,m)=1结束
*/
ll qgcd(ll n,ll m)
{
if(n<m) swap(n,m);//保证n>=m;
return m==1?n:(qgcd(n/m,m));
}
ll a[N],up[N],dw[N];
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%lld",&a[i]);
sort(a,a+n);//排序
n=unique(a,a+n)-a;//去重
for(int i=1;i<n;i++) //相邻两项的比值 a[i]/a[i-1]
{
ll g=gcd(a[i-1],a[i]);
up[i]=a[i]/g;
dw[i]=a[i-1]/g;
}
for(int i=2;i<n;i++)
{
up[1]=qgcd(up[1],up[i]);
dw[1]=qgcd(dw[1],dw[i]);
}
printf("%lld/%lld\n",up[1],dw[1]);
return 0;
}