2016年第七届蓝桥杯省赛(C/C++ A组)

此处有目录↑


基本都是暴力搜索解决,最后两道算法题不会 - -


1.父亲和儿子 (枚举)

父亲年龄是两位数,且比儿子大27岁,问有多少种可能的情况?(父亲30岁,儿子3岁也符合题意)


直接枚举父亲年龄即可

答案是:7

[cpp]  view plain
  1. #include <cstdio>  
  2.   
  3. using namespace std;  
  4.   
  5. int main() {  
  6.     int ans=0;  
  7.     for(int i=1;i<=9;++i)  
  8.         for(int j=0;j<=9;++j)  
  9.             if(10*i+j-10*j-i==27)  
  10.                 ++ans;  
  11.     printf("%d\n",ans);  
  12. }  

2.生日蜡烛 (枚举)

一个人从某一岁开始每年生日都在蛋糕上插上与年龄数值相同的蜡烛,下载他总共插了236根蜡烛,问他从多少岁时开始插蜡烛?


直接从1岁开始枚举,找到答案就停止

不过这样答案是:26,后来看到网上说236也可以,这估计是个坑点

[cpp]  view plain
  1. #include <cstdio>  
  2.   
  3. using namespace std;  
  4.   
  5. int solve() {  
  6.     int sta=0,sum,cur;  
  7.     while(1) {  
  8.         sum=cur=sta;  
  9.         while(sum<236)  
  10.             sum+=++cur;  
  11.         if(sum==236)  
  12.             return sta;  
  13.         ++sta;  
  14.     }  
  15. }  
  16.   
  17. int main() {  
  18.     printf("%d\n",solve());  
  19. }  


3.填格子 (DFS)

有一个含有10个格子的图形,现用0~9填充,连续的数不能填充在相邻的格子中(包括对角线相邻),问有多少种填充方法?


dfs即可,注意剪枝,就能秒出

不过我认为每个数字只能填一次,算出来是:1580

[cpp]  view plain
  1. #include <cstdio>  
  2. #include <algorithm>  
  3.   
  4. using namespace std;  
  5.   
  6. int grid[7][7],ans;  
  7. bool vis[11];  
  8.   
  9. const int dr[4]={0,-1,-1,-1};//当前格子的正左、左上、正右、右上  
  10. const int dc[4]={-1,-1,0,1};  
  11.   
  12. bool isAvailable(int r,int c,int n) {  
  13.     for(int i=0;i<4;++i)  
  14.         if(abs(grid[r][c]-grid[r+dr[i]][c+dc[i]])<=1)  
  15.             return false;  
  16.     return true;  
  17. }  
  18.   
  19. void dfs(int r,int c) {  
  20.     if(r==3&&c==4)  
  21.         ++ans;  
  22.     for(int i=0;i<=9;++i) {  
  23.         grid[r][c]=i;  
  24.         if(!vis[i]&&isAvailable(r,c,i)) {  
  25.             vis[i]=true;  
  26.             int rr=r,cc=c+1;  
  27.             if(cc>4) {  
  28.                 ++rr;  
  29.                 cc=1;  
  30.             }  
  31.             dfs(rr,cc);  
  32.             vis[i]=false;  
  33.         }  
  34.         grid[r][c]=-9;  
  35.     }  
  36. }  
  37.   
  38. int main() {  
  39.     for(int i=0;i<7;++i) {  
  40.         for(int j=0;j<7;++j) {  
  41.             grid[i][j]=-9;  
  42.         }  
  43.         vis[i]=false;  
  44.     }  
  45.     vis[7]=vis[8]=vis[9]=false;  
  46.     ans=0;  
  47.     dfs(1,2);  
  48.     printf("%d\n",ans);  
  49. }  

4.快速排序

数据结构学过,这么快又忘了,还看了半天...

swap(a,p,j);


5.去掉尾1

如果一个数二进制表示时,若个位是1,则去掉从个位起开始的连续的1,若个位不是1,则不变

答案是:x&(x+1)

很简单的答案,可是当时一点都没想到,自己想的是用3元运算符,连续嵌套31次实现这个功能,由于每次代码都一样,所以用循环生成代码,最后交了700多B...


6.四则运算 (DFS)

有1~13共13个数,将12个不同的数填入下列12个空使四个运算都成立,问有多少种方法?


依旧是dfs+剪枝就能秒出,答案是:64,感觉当时写的不是64,估计当时拷代码时有地方没改 :(

[cpp]  view plain
  1. #include <cstdio>  
  2.   
  3. using namespace std;  
  4.   
  5. int a[15],ans;  
  6. bool vis[15];  
  7.   
  8. void dfs(int dep) {  
  9.     if(dep==3) {  
  10.         if(a[1]/a[2]*a[2]==a[1]&&a[1]/a[2]>0&&!vis[a[1]/a[2]]) {  
  11.             vis[a[1]/a[2]]=true;  
  12.             dfs(4);  
  13.             vis[a[1]/a[2]]=false;  
  14.         }  
  15.         return ;  
  16.     }  
  17.     if(dep==6) {  
  18.         if(a[4]*a[5]<=13&&!vis[a[4]*a[5]]) {  
  19.             vis[a[4]*a[5]]=true;  
  20.             dfs(7);  
  21.             vis[a[4]*a[5]]=false;  
  22.         }  
  23.         return ;  
  24.     }  
  25.     if(dep==9) {  
  26.         if(a[7]+a[8]<=13&&!vis[a[7]+a[8]]) {  
  27.             vis[a[7]+a[8]]=true;  
  28.             dfs(10);  
  29.             vis[a[7]+a[8]]=false;  
  30.         }  
  31.         return ;  
  32.     }  
  33.     if(dep==12) {  
  34.         if(a[10]+a[11]<=13&&!vis[a[10]+a[11]])  
  35.             ++ans;  
  36.         return ;  
  37.     }  
  38.     for(int i=1;i<=13;++i) {  
  39.         if(!vis[i]) {  
  40.             vis[i]=true;  
  41.             a[dep]=i;  
  42.             dfs(dep+1);  
  43.             vis[i]=false;  
  44.         }  
  45.     }  
  46. }  
  47.   
  48. int main() {  
  49.     ans=0;  
  50.     dfs(1);  
  51.     printf("%d\n",ans);  
  52. }  



7.剪邮票 (DFS)

有一个3*4的十二生肖邮票,剪下连续的5个(对角相连不算),问有多少种方法?


dfs即可,只需要注意判重(当时先用map[已经排过序],结果不管一种剪法出现多少次都是显示为出现,最后自己写了个暴力判断才行...)

答案是:116

[cpp]  view plain
  1. #include <cstdio>  
  2. #include <vector>  
  3. #include <algorithm>  
  4.   
  5. using namespace std;  
  6.   
  7. int ans;  
  8. bool vis[5][5];  
  9.   
  10. struct Node {  
  11.     int n;  
  12.     pair<int,int> p[5];  
  13.     bool operator ==(const Node& a) const {  
  14.         for(int i=0;i<5;++i)  
  15.             if(p[i].first!=a.p[i].first||p[i].second!=a.p[i].second)  
  16.                 return false;  
  17.         return true;  
  18.     }  
  19. };  
  20.   
  21. vector<Node> tmp;  
  22.   
  23. const int dr[4]={-1,0,1,0};  
  24. const int dc[4]={0,1,0,-1};  
  25.   
  26. inline bool isInside(int r,int c) {  
  27.     return 0<=r&&r<3&&0<=c&&c<4;  
  28. }  
  29.   
  30. inline bool isOk(const Node& cur) {  
  31.     for(int i=0;i<tmp.size();++i)  
  32.         if(cur==tmp[i])  
  33.             return false;  
  34.     return true;  
  35. }  
  36.   
  37. void dfs(Node cur) {  
  38.     if(cur.n==5) {  
  39.         sort(cur.p,cur.p+5);  
  40.         if(isOk(cur)) {  
  41.             ++ans;  
  42.             tmp.push_back(cur);  
  43.         }  
  44.         return ;  
  45.     }  
  46.     int num=cur.n++;  
  47.     for(int i=0;i<num;++i) {  
  48.         for(int j=0;j<4;++j) {  
  49.             int rr=cur.p[i].first+dr[j],cc=cur.p[i].second+dc[j];  
  50.             if(isInside(rr,cc)&&!vis[rr][cc]) {  
  51.                 vis[rr][cc]=true;  
  52.                 cur.p[num].first=rr;  
  53.                 cur.p[num].second=cc;  
  54.                 dfs(cur);  
  55.                 vis[rr][cc]=false;  
  56.             }  
  57.         }  
  58.     }  
  59.     --cur.n;  
  60. }  
  61.   
  62. int main() {  
  63.     ans=0;  
  64.     Node cur;  
  65.     cur.n=1;  
  66.     for(int i=0;i<3;++i) {  
  67.         cur.p[0].first=i;  
  68.         for(int j=0;j<4;++j) {  
  69.             cur.p[0].second=j;  
  70.             vis[i][j]=true;  
  71.             dfs(cur);  
  72.             vis[i][j]=false;  
  73.         }  
  74.     }  
  75.     printf("%d\n",ans);  
  76. }  


8.四方定理 (枚举)

所有自然数至多只要用四个数的平方和就可以表示,若可以用0补齐空位,则所有自然数都可以用四个数的平方和表示,现在将这四个数按升序排序,取第一个数最小的作为答案,问答案是多少?

前面都用的dfs,所以这题当时也用了dfs的形式,但是最后没想到上限取错了,估计要wa很多数据

会做的题,就这题太遗憾了 :(

[cpp]  view plain
  1. #include <cstdio>  
  2. #include <cmath>  
  3.   
  4. using namespace std;  
  5.   
  6. int a[5],tmp[5],n;  
  7.   
  8. void solve() {  
  9.     for(a[0]=0;a[0]<=1119;++a[0]) {//a[0]的上限为 sqrt(5000 000/4)  
  10.         tmp[0]=n-a[0]*a[0];  
  11.         if(a[0]>=0) {  
  12.             for(a[1]=a[0];a[1]<=1291;++a[1]) {//a[1]的上限为 sqrt(5000 000/3)  
  13.                 tmp[1]=tmp[0]-a[1]*a[1];  
  14.                 if(a[1]>=0) {  
  15.                     for(a[2]=a[1];a[2]<=1582;++a[2]) {//a[2]的上限为 sqrt(5000 000/2)  
  16.                         tmp[2]=tmp[1]-a[2]*a[2];  
  17.                         a[3]=sqrt((double) tmp[2]);  
  18.                         if(a[3]>=a[2]&&a[3]*a[3]==tmp[2])  
  19.                             return;  
  20.                     }  
  21.                 }  
  22.             }  
  23.         }  
  24.     }  
  25. }  
  26.   
  27. int main() {  
  28.     scanf("%d",&n);  
  29.     solve();  
  30.     printf("%d %d %d %d\n",a[0],a[1],a[2],a[3]);  
  31. }  


9.回文串 (区间DP||最小回文代价)

有一个只含有A,B,C,D的字符串,问最少插入几个字符能使其成为回文串?


正解是:

①区间DP

当时不会(准确说仍然不会,以前只写过一次,完全忘了),用O(2^n)暴力,希望能骗一点点分...


待完成……

②最小回文代价 (经典例题)

计算原字符串与逆序字符串的LCS(最长公共子序列)的长度,用字符串长度减去LCS的长度就是最小回文代价

10.最大公比

给一个数列其中几项(可能会重复),求这个数列的最大公比?


还不知道正解如何做

当时想的是去重排序后,所有相邻数之间的比值的最大公约数,但是直接求最大公约数貌似会爆long long,然后就不知道怎么办了,用了一种很奇怪的方法,最后没写完交了。

转载:http://blog.csdn.net/idealism_xxm/article/details/50937688

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值