之前一次撸完题解,复制记事本上题目的时候这网页卡住了(撤回都撤回不了),回来啥都没了,在线自闭。再写就懒了,就写那些让我好好思考的题的题解。看最近蓝桥杯的访问量较多,还是决定把题补全,但会没题目,只有答案和注释里的题解。
1.煤球数量
简单的前缀和
答案:171700
#include <iostream>
using namespace std;
int main()
{
long long int i,ans[110];
ans[1]=1;
for(i=2;i<=100;i++)
ans[i]=ans[i-1]+i;
for(i=2;i<=100;i++)
ans[i]+=ans[i-1];
cout<<ans[100];
return 0;
}
2.生日蜡烛
又是简单的前缀和,但要注意答案加一,前缀和剪掉的是上一年的结尾。
答案:26 说不定他就活到了236岁呢
#include <iostream>
using namespace std;
int main()
{
int num[100],i,j;
num[0]=0;
for(i=1;i<=100;i++)
num[i]=num[i-1]+i;
for(i=100;i>=0;i--)
for(j=0;j<=100;j++)
if(num[i]-num[j]==236)
{
cout<<j+1<<endl;
return 0;
}
}
3.凑算式
全排列暴力 暴力大法好
反正题目里没有0,随便排(网上查的没0,学校给的有0,反正我偷懒写没0的)
next_permutation(a+1,a+10)是algorithm头文件下的一个全排列函数,也是在这才学会的。
注意do while
答案:29
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
int main()
{
double n1,n2;
int a[10],i,ans=0;
for(i=1;i<10;i++)
a[i]=i;
do
{
n1=1.0*a[2]/a[3];
n2=1.0*(100*a[4]+10*a[5]+a[6])/(100*a[7]+10*a[8]+a[9]);
if(fabs(a[1]+n1+n2-10)<1e-6) ans++;
}while(next_permutation(a+1,a+10));
cout<<ans<<endl;
return 0;
}
4.快速排序
没啥好讲的,快排都做烂了,看懂过程就行。
**答案:swap(a,p,j); **
5.抽签
抽签
X星球要派出一个5人组成的观察团前往W星。
其中:
A国最多可以派出4人。
B国最多可以派出2人。
C国最多可以派出2人。
…
那么最终派往W星的观察团会有多少种国别的不同组合呢?
下面的程序解决了这个问题。
数组a[] 中既是每个国家可以派出的最多的名额。
程序执行结果为:
DEFFF
CEFFF
CDFFF
CDEFF
CCFFF
CCEFF
CCDFF
CCDEF
BEFFF
BDFFF
BDEFF
BCFFF
BCEFF
BCDFF
BCDEF
…
(以下省略,总共101行)
#include <stdio.h>
#define N 6
#define M 5
#define BUF 1024
void f(int a[],int k,int m,char b[])
{
int i,j;
if(k==N)
{
b[M]=0;
if(m==0) printf("%s\n",b);
return;
}
for(i=0;i<=a[k];i++)
{
for(j=0; j<i; j++)
b[M-m+j]=k+'A';
f(a,k+1,m-j,b);
}
}
int main()
{
int a[N]={4,2,2,1,1,3};
char b[BUF];
f(a,0,M,b);
return 0;
}
解:
此类填空题的核心是看懂实参形参的含义:
f(数组首地址,国家,剩余人数,数组首地址)
6.方格填数
答案:1580
解:
暴力填入,dfs判断是否正确(暴力大法好)
#include <iostream>
#include <cmath>
using namespace std;
int aa[3][4],dir[8][2]={1,0,-1,0,0,1,0,-1,1,1,1,-1,-1,1,-1,-1},vis[10],ans;
bool check()//判断
{
int i,j,k;
for(i=0;i<3;i++)
for(j=0;j<4;j++)
for(k=0;k<8;k++)
{
int x=i+dir[k][0],y=j+dir[k][1];
if(x>=0&&x<=2&&y>=0&&y<=3)
if(abs(aa[x][y]-aa[i][j])==1)
return false;
}
return true;
}
void func(int a,int b)//填入
{
int i,j;
if(a==2&&b==3)
{
if(check()) ans++;
return;
}
for(i=0;i<=9;i++)
if(!vis[i])
{
vis[i]=1;
aa[a][b]=i;
if(b==3) func(a+1,0);
else func(a,b+1);
vis[i]=0;
}
}
int main()
{
aa[0][0]=0x7fffffff;
aa[2][3]=0x7fffffff;
func(0,1);
cout<<ans;
return 0;
}
7.剪邮票
如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】【图3.jpg】中,粉红色所示部分就是合格的剪取。
请你计算,一共有多少种不同的剪取方法。
答案:116
解:
关键是如何找出并不重复。还是暴力枚举然后dfs判断。
为防止重复可以保持从小到大的顺序枚举,再判断其是否是联通即可。
#include <iostream>
#include <cstring>
using namespace std;
bool vis[13];
int note[5],dir[4][2]={1,0,-1,0,0,1,0,-1},ans,count,mp[4][5];
void dfs(int a,int b)//搜索
{
if(count==5) return; //枚举的5个数联通
int i,j;
for(i=0;i<4;i++)
{
int x=a+dir[i][0],y=b+dir[i][1];
if(x>=1&&x<=3&&y>=1&&y<=4&&!vis[mp[x][y]])
for(j=0;j<5;j++)
if(mp[x][y]==note[j])
{
count++;
vis[note[j]]=true;
dfs(x,y);
}
}
}
int main()
{
for(int i=1;i<=3;i++)
for(int j=1;j<=4;j++)
mp[i][j]=(i-1)*4+j;//生成图1,用于dfs搜索
for(int i=1;i<=8;i++)
{
note[0]=i;
for(int j=i+1;j<=9;j++)
{
note[1]=j;
for(int k=j+1;k<=10;k++)
{
note[2]=k;
for(int l=k+1;l<=11;l++)
{
note[3]=l;
for(int m=l+1;m<=12;m++)
{
memset(vis,false,sizeof(vis));
note[4]=m; //枚举填入
vis[i]=true;
count=1;
dfs((i-1)/4+1,(i-1)%4+1); //找出对应坐标用于搜索
if(count==5) ans++;
}
}
}
}
}
cout<<ans;
return 0;
}
8.四平方和
暴力一下 不知道可不可以过,
#include <iostream>
using namespace std;
int n,i,j,k,l;
void func()
{
for(i=0;i*i<=n;i++)
for(j=i;i*i+j*j<=n;j++)
for(k=j;i*i+j*j+k*k<=n;k++)
for(l=k;i*i+j*j+k*k+l*l<=n;l++)
if(i*i+j*j+k*k+l*l==n)
{
cout<<i<<" "<<j<<" "<<k<<" "<<l;
return;
}
}
int main()
{
cin>>n;
func();
return 0;
}
9.交换瓶子
标准贪心,从前往后,哪个位置不对,就和后面对应的换。
#include <iostream>
using namespace std;
void swap(int a[],int b,int c)//交换,话说algorithm里好像有swap函数
{
int t=a[b];
a[b]=a[c];
a[c]=t;
}
int main()
{
int a[10010],n,i,j,ans=0,loca[10010];
cin>>n;
for(i=1;i<=n;i++)
{
cin>>a[i];//输入
loca[a[i]]=i;//每个瓶子的位置,便于O(1)查询
}
for(i=1;i<=n;i++)
{
if(loca[i]==i) continue;//位置对则继续
loca[a[i]]=loca[i];//换位置的值
swap(a,i,loca[i]);//换值
ans++;
loca[i]=i;
}
cout<<ans<<endl;
return 0;
}
10.最大比例
X星球的某个大奖赛设了M级奖励。每个级别的奖金是一个正整数。
并且,相邻的两个级别间的比例是个固定值。
也就是说:所有级别的奖金数构成了一个等比数列。比如:
16,24,36,54
其等比值为:3/2
现在,我们随机调查了一些获奖者的奖金数。
请你据此推算可能的最大的等比值。
输入格式:
第一行为数字N,表示接下的一行包含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 , 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。
解:
题意:现在有一堆被打乱了的等比数列,有的数可能缺,有的数可能出现多次,要你找可能存在的最大公比。
所以先升序排列并排除重复的数字,形成一个残缺的等比数列。前后相除得出比(分数形式,找最大公因数约分,分子分母分开存,对分子分母分开处理结果不变),定义最大公比为q,把他们看成qa1,qa2……(此时所有的数都与某一数成倍数关系)找出a1,a2,a3……an的最大公因数(不是qa1,qa2……的)即可,最后分别输出分子和分母的q。(解法:对a1,a2,a3……an用辗转相减,指数相减相当于原数相除)。
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long int ll;
ll gcd(ll a,ll b)//辗转相除
{
return b? gcd(b,a%b):a;
}
ll gcdjian(ll a,ll b)//辗转相减的另一种使用
{
if(a==b) return a;
if(a>b) return gcdjian(b,a/b);
else return gcdjian(b,a);
}
int main()
{
ll n,i,j,a[10000],a1[10000],a2[10000],t1,t2,ans1,ans2,len=0;
double ans=0x7fffffff;
cin>>n;
for(i=0;i<n;i++)
cin>>a[i];
sort(a,a+n);
for(i=1;i<n;i++)
{
if(a[i]==a[i-1]) continue;
t1=gcd(a[i],a[i-1]);
a1[++len]=a[i]/t1;a2[len]=a[i-1]/t1;//约分
}
t1=a1[1];t2=a2[1];
for(i=2;i<=len;i++)
{
t1=gcdjian(t1,a1[i]);
t2=gcdjian(t2,a2[i]);
}
cout<<t1<<"/"<<t2;
return 0;
}
时间复杂度怎样我不会算。。不知道能不能过,感觉没问题