[关闭]
@Moritz 2019-03-26T04:33:42.000000Z 字数 4131 阅读 414

第八届蓝桥杯C/C++A组省赛

蓝桥杯 C++ 编程 竞赛 所有文稿


8.包子凑数

小明几乎每天早晨都会在一家包子铺吃早餐。他发现这家包子铺有N种蒸笼,其中第i种蒸笼恰好能放Ai个包子。每种蒸笼都有非常多笼,可以认为是无限笼。

每当有顾客想买X个包子,卖包子的大叔就会迅速选出若干笼包子来,使得这若干笼中恰好一共有X个包子。比如一共有3种蒸笼,分别能放3、4和5个包子。当顾客想买11个包子时,大叔就会选2笼3个的再加1笼5个的(也可能选出1笼3个的再加2笼4个的)。

当然有时包子大叔无论如何也凑不出顾客想买的数量。比如一共有3种蒸笼,分别能放4、5和6个包子。而顾客想买7个包子时,大叔就凑不出来了。

小明想知道一共有多少种数目是包子大叔凑不出来的。

输入
第一行包含一个整数N。(1 <= N <= 100)
以下N行每行包含一个整数Ai。(1 <= Ai <= 100)

输出
一个整数代表答案。如果凑不出的数目有无限多个,输出INF。

拓展欧几里得:一定存在(x,y)使得ax+by=gcd(a,b)

本题题意需要满则x>=0,y>=0(即包子的笼数是非负的);也就是说,如果gcd(a,b)的值为1,那么对于任意的数值方程两边只需要乘以一个整数 ,即可凑出。这时候取决a和b的取值凑不出的情况就对应是系数是负值的情况。 当max(a,b,....)…………^2能够凑出后,以后所有的都可以凑出。因此检验到1e4即可。

如果gcd(a,b)的值不为1,
那么一定有所有的gcd(a,b)的正整数倍的数值是能够凑出来的。同样也有无数个数值是凑不出的。

  1. /*3.3 21:12-21:38 背包问题*/
  2. /*3.20 20:47*/
  3. #include <iostream>
  4. #include <cmath>
  5. #include <algorithm>
  6. #include <cstdio>
  7. #include <set>
  8. #include <string.h>
  9. using namespace std;
  10. const int maxn=110;
  11. int a[maxn],dp[10010],n,m=150;
  12. int gcd(int a, int b){//最大公因数
  13. return b == 0 ? a : gcd(b, a%b);
  14. }
  15. int main(){
  16. memset(dp,0,sizeof(dp));
  17. cin>>n;
  18. for(int i=0;i<n;i++) {cin>>a[i];}
  19. /*用辗转相除法求几个数的最大公约数,可以先求出其中任意两个数的最大公约数,再求这个最大公约数与第三个数的最大公约数,依次求下去,直到最后一个数为止。最后所得的那个最大公约数,就是所有这些数的最大公约数*/
  20. int g = a[0];
  21. for(int i = 1; i < n; i++){
  22. g = gcd(g, a[i]);
  23. }
  24. if (g==1){
  25. sort(a,a+n);
  26. dp[0]=1;
  27. for(int i = 0; i < n; i++){
  28. for(int j = 0; j+a[i] < 100*100+5; j++){
  29. if(dp[j]) dp[j+a[i]] = 1;
  30. }
  31. }
  32. long long cnt=0;
  33. for(int i=1;i<10010;i++) if(dp[i]==0) cnt++;
  34. cout<<cnt<<endl;
  35. }
  36. else cout<<"INF"<<endl;
  37. return 0;
  38. }

9.分巧克力

儿童节那天有K位小朋友到小明家做客。小明拿出了珍藏的巧克力招待小朋友们。
小明一共有N块巧克力,其中第i块是Hi x Wi的方格组成的长方形。

为了公平起见,小明需要从这 N 块巧克力中切出K块巧克力分给小朋友们。切出的巧克力需要满足:

1. 形状是正方形,边长是整数  
2. 大小相同  

例如一块6x5的巧克力可以切出6块2x2的巧克力或者2块3x3的巧克力。

当然小朋友们都希望得到的巧克力尽可能大,你能帮小Hi计算出最大的边长是多少么?

输入
第一行包含两个整数N和K。(1 <= N, K <= 100000)
以下N行每行包含两个整数Hi和Wi。(1 <= Hi, Wi <= 100000)
输入保证每位小朋友至少能获得一块1x1的巧克力。

输出
输出切出的正方形巧克力最大可能的边长。

样例输入:
2 10
6 5
5 6

样例输出:
2

直接暴力,AC

  1. /*21:30*/
  2. /*21:48*/
  3. #include <iostream>
  4. #include <algorithm>
  5. using namespace std;
  6. const int maxn=100000;
  7. pair<int,int> a[maxn];
  8. int main(){
  9. int n,k,len=0;
  10. cin>>n>>k;
  11. for(int i=0;i<n;i++){
  12. int x,y;
  13. cin>>x>>y;
  14. a[i]=make_pair(x,y);
  15. if (x>len) len=x;
  16. if (y>len) len=y;
  17. }
  18. for(int c=len;c>=1;c--){
  19. int tot=0;
  20. bool found=false;
  21. for(int i=0;i<n;i++){
  22. if (a[i].first*a[i].second>c*c){
  23. int n1=a[i].first/c,n2=a[i].second/c;
  24. tot+=n1*n2;
  25. }
  26. if (tot>=k){
  27. cout<<c;
  28. system("pause");
  29. return 0;}
  30. }
  31. }
  32. system("pause");
  33. return 0;
  34. }

更好的解题思路:用二分搜索化查找为判定的前提条件是答案具有单调性,很显然本题巧克力的边长具有单调性,故可以用二分搜索解法。

优化算法后:87分,最后一个案例未通过,debug中

  1. /*21:56-22:15*/
  2. /*20:02-20:38*/
  3. #include <iostream>
  4. #include <algorithm>
  5. #include <cstdio>
  6. #include <string.h>
  7. using namespace std;
  8. const int maxn=100000;
  9. int a[maxn][2];
  10. int n,k,len=0;
  11. bool find_len(int c){
  12. int tot=0;
  13. for(int i=0;i<n;i++){
  14. if (a[i][0]*a[i][1]>=c*c){
  15. int n1=a[i][0]/c,n2=a[i][1]/c;
  16. tot+=n1*n2;
  17. }
  18. if (tot>=k){
  19. return true;
  20. }
  21. }
  22. return false;
  23. }
  24. int main(){
  25. memset(a,0,sizeof(a));
  26. cin>>n>>k;
  27. for(int i=0;i<n;i++){
  28. cin>>a[i][0]>>a[i][1];
  29. len=max(a[i][0],max(a[i][1],len));
  30. }
  31. int l=1,r=len;
  32. //cout<<endl<<r<<endl;
  33. while(l<r-1){
  34. int mid=l-(l-r)/2;
  35. if(find_len(mid)) l=mid;
  36. else r=mid-1;
  37. if(r-l==1){
  38. if (find_len(r)) cout<<r;
  39. else cout<<l;
  40. break;
  41. //printf("l=%d r=%d\n",l,r);
  42. }
  43. }
  44. system("pause");
  45. return 0;
  46. }

需要注意:二分搜索中mid的加一减一问题,且输出为搜索结果-1

另外,二分搜索如果使用mid=(high+low)/2可能会出现数据溢出问题,改为用mid=low+(high-low)/2则不会有该问题


10.油漆问题

以下程序一个错误,两个超时,bug未知

  1. /*19.3.5 12:40-13:00*/
  2. #include <iostream>
  3. #include <map>
  4. using namespace std;
  5. map<pair<int,int>,int> spa;
  6. int main(){
  7. int n,tot=0;
  8. cin>>n;
  9. for(int i=0;i<n;i++) {
  10. pair<int,int> p1,p2;
  11. cin>>p1.first>>p1.second>>p2.first>>p2.second;
  12. int min_x=min(p1.first,p2.first);
  13. int min_y=min(p1.second,p2.second);
  14. int max_x=max(p1.first,p2.first);
  15. int max_y=max(p1.second,p2.second);
  16. for(int x=min_x+1;x<=max_x;x++){
  17. for(int y=min_y+1;y<=max_y;y++){
  18. if (!spa.count(make_pair(x,y))) {tot++;}
  19. spa[(make_pair(x,y))]=1;
  20. }
  21. }
  22. }
  23. cout<<spa.size();
  24. return 0;
  25. }

改成用数组,注意面积数组用bool(听说测试数据有问题,应该是全通过的)

  1. #include <iostream>
  2. #include <string.h>
  3. #include <cstdio>
  4. using namespace std;
  5. int x_1[10010],x_2[10010],y_1[10010],y_2[10010];
  6. bool a[10010][10010];
  7. int main(){
  8. memset(a,0,sizeof(a));
  9. memset(x_1,0,sizeof(x_1));
  10. memset(x_2,0,sizeof(x_2));
  11. memset(y_1,0,sizeof(y_1));
  12. memset(y_2,0,sizeof(y_2));
  13. long long n,tot=0;
  14. cin>>n;
  15. for(int i=0;i<n;i++) {
  16. scanf("%d%d%d%d",&x_1[i],&y_1[i],&x_2[i],&y_2[i]);
  17. if (x_2[i]<x_1[i]) {int t=x_2[i];x_2[i]=x_1[i];x_1[i]=t;}
  18. if (y_2[i]<y_1[i]){int t=y_2[i];y_2[i]=y_1[i];y_1[i]=t;}
  19. }
  20. for(int i=0;i<n;i++){
  21. for(int x=x_1[i];x<x_2[i];x++){
  22. for(int y=y_1[i];y<y_2[i];y++){
  23. if (!a[x][y]) {tot++;a[x][y]=1;}
  24. }
  25. }
  26. }
  27. cout<<tot;
  28. return 0;
  29. }

2019.3.22

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注