【洛谷新手村解题报告四 共五题】C++语言,思路和WA反思

【洛谷新手村解题报告四 】

  • 过程函数与递归
  • BOSS战-入门综合练习1

从递归的第三题开始了!

过程函数与递归

第三题 火柴棒等式[2,1]
【洛谷新手村解题报告四 共五题】C++语言,思路和WA反思_第1张图片
这里介绍最简单的 便于理解的方法:
Sol 1 暴力枚举
因为n最大24 我们计算所有的四位数需要的火柴棒数量预处理
计算的时候 每一位需要的火柴棒数量可以int cnt[]={6,2,5,5,4,5,6,3,7,6};
最后计算的时候,枚举A 和 B
如果 数字A B A+B 的火柴棒数量=n-4 就是一个解(因为加号和等号都是两根)

Sol 2 打表
int f[25]={0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,8,9,6,9,29,39…………};
24根列完就OK了!

第四题 回文质数 Prime Palindromes[2,1]

写一个程序来找出范围[a,b] (5≤a

提示已经给了,先列举回文数,再判断是否为质数
这里有个神奇的小东西:
除了11,所有的偶数位数的回文数都是非质数,都被11整除
那我们枚举其他奇数位的回文数,再判断是否是质数就可以了!
列举长度为7的回文数:

for (int d1 = 1; d1 <= 9; d1+=2){		//偶数一定不是质数,最低(高)位一定是偶数
  for (int d2 = 0; d2 <= 9; d2++){
      for (int d3 = 0; d3 <= 9; d3++){
          for(int d4=0;d4<=9;d4++){
              pal = 1000000*d1 + 100000*d2 +10000*d3 + 1000*d4 +100*d3+ 10*d2 + d1;
              if(pal<a || pal>b)continue;				//判断要在范围内
              if(ck(pal))printf("%lld\n",pal);			//判断质数
          }
      }
  }
}

BOSS战-入门综合练习1

第一题 陶陶摘苹果(升级版)[2,2]

又是一年秋季时,陶陶家的苹果树结了 n 个果子。陶陶又跑去摘苹果,这次他有一个 a 公分的椅子。当他手够不着时,他会站到椅子上再试试。
这次与 NOIp2005 普及组第一题不同的是:陶陶之前搬凳子,力气只剩下 s 了。当然,每次摘苹果时都要用一定的力气。陶陶想知道在s<0 之前最多能摘到多少个苹果。
现在已知 n 个苹果到达地上的高度 xi ,椅子的高度 a,陶陶手伸直的最大长度 b,陶陶所剩的力气s,陶陶摘一个苹果需要的力气 yi,求陶陶最多能摘到多少个苹果。

既然只输出最多摘多少个苹果,那我们就贪心,每次摘需要花费力气最小的苹果,如果摘不到就下一个力气次小的,依次类推
每个苹果有高度和力气两个参数,我们使用简便的pairP[MAX];
cmp()函数比较每个苹果的力气值,然后顺序摘取

第二题 三连击(升级版)[1,1]
之前的三连击题目一样,只不过比例改成了自定义输入,同之前的代码
解题报告一,三连击在里面

第三题 哥德巴赫猜想(升级版)[2,2]

1742年6月7日哥德巴赫写信给当时的大数学家欧拉,正式提出了以下的猜想:任何一个大于9的奇数都可以表示成3个质数之和。质数是指除了1和本身之外没有其他约数的数,如2和11都是质数,而6不是质数,因为6除了约数1和6之外还有约数2和3。需要特别说明的是1不是质数。

因为范围 9 用埃筛即可,原理:i是素数的话,i*k(正整数) 一定不是素数,则可以筛去
复杂度O(NlogN)

int shai(void){
    int p=-1;
    for(int i=2;i<MAX;++i){
        if(num[i])continue;				//记录i有没有被筛走
        pri[++p]=i;						//下一个质数是i
        for(int j=i*2;j<MAX;j+=i)		//k倍都筛掉
            num[j]=1;					//j筛走了
    }
    return p;
}

然后枚举 质数 a b ,是否 n-a-b 也是质数即可

第四题 烤鸡[3,3]

猪猪 Hanke 特别喜欢吃烤鸡(本是同畜牲,相煎何太急!)Hanke 吃鸡很特别,为什么特别呢?因为他有 10种配料(芥末、孜然等),每种配料可以放 1 到 3 克,任意烤鸡的美味程度为所有配料质量之和。
现在, Hanke 想要知道,如果给你一个美味程度 n ,请输出这 10 种配料的所有搭配方案。
输入
11
输出
10
1 1 1 1 1 1 1 1 1 2
1 1 1 1 1 1 1 1 2 1
1 1 1 1 1 1 1 2 1 1
1 1 1 1 1 1 2 1 1 1
1 1 1 1 1 2 1 1 1 1
1 1 1 1 2 1 1 1 1 1
1 1 1 2 1 1 1 1 1 1
1 1 2 1 1 1 1 1 1 1
1 2 1 1 1 1 1 1 1 1
2 1 1 1 1 1 1 1 1 1

有一定难度的递归题目,答案还要求字典序升序输出
首先我采用了状态压缩做法(每种调料使用1/2/3 三种状态)3^10 也没超时间
试试就逝世
一通狂做,一看输出傻眼了:(最后答案反转了一下输出的)
【洛谷新手村解题报告四 共五题】C++语言,思路和WA反思_第2张图片
这咋就这么奇怪呢?状态压缩是二进制方法实现的,二进制不保证字典序!
那就利用递归好好做吧

void pd(int pos,int now) 表示当前位置为pos ,用了调料now了
边界1 : 如果pos=10 表示处理完了 如果now!=n 表示用的不对,反之输出
边界2 优化: 如果当前位置和以后位置都放3都放不完调料了,跳出
边界3 优化 : 如果当前位置now>n 了,那表示再怎么放都不对了,跳出
处理 :这位放1 继续递归 这位放2 继续递归 这位放3 继续递归
思路很好理解,那就贴代码吗(呜呜当时调了很久 我好菜)

void pd(int pos,int now){
    if(pos==10){					//边界1
        if(now!=n)return;
        ans++;
        for(int i=1;i<=10;++i){
            aa[ans][i]=cas[i];		//第ans种情况,先存起来
        }
        return ;
    }
    if(now>n)return ;				//边界3
    if(10-pos + now > n || (10-pos)*3 + now <n)return ;		//边界2
    cas[pos+1]=1;					//这位放1 递归,下同理
    pd(pos+1,now+1);
    cas[pos+1]=2;
    pd(pos+1,now+2);
    cas[pos+1]=3;
    pd(pos+1,now+3);
    return ;
}

求个赞拉 写了这么多

你可能感兴趣的:(【洛谷新手村解题报告四 共五题】C++语言,思路和WA反思)