A - Link/Cut Tree,C - Maximum Product,E - 组合的输出 题目描述+参考代码+代码讲解——中山大学软件工程学院专选算法课第三次实验 必做题

现在处于一个混乱的{ }中间态,有时换行有时不换行...

换行确实看起来更简洁。但是不换行看起来更完整。怪不得学C的能为这个问题吵起来。

先把必做题做了,就是抓住了主要矛盾

 A - Link/Cut Tree

题目描述

参考代码

#include
#include
using namespace std;
#define ll long long
ll getAns(ll k,ll p){
    ll ans=1;
    for(int i=1;i<=p;i++)
        ans*=k;
    return ans;
}
int main()
{
    ll l,r,k,p;
    while(cin>>l>>r>>k)
    {
        p=0;
        bool legal=false;
        while(true){
            if(pow(k,p)>r)
                break;
            if( pow(k,p)>=l && pow(k,p)<=r ){
                cout<

代码讲解

妙处

我觉得第一个巧妙点在#define ll long long 毕竟long long写起来太长了。

第二个看起来笨,但实际上巧妙的是单独用一个函数算出ans值。

两个容易踩的坑

1.不能直接输出pow的结果,因为那会用科学计数法来表示。

cout<

 2.不能先乘再看符不符合条件,ans *= k也超过 long long了!

A - Link/Cut Tree,C - Maximum Product,E - 组合的输出 题目描述+参考代码+代码讲解——中山大学软件工程学院专选算法课第三次实验 必做题_第1张图片

C - Maximum Product

题目描述

A - Link/Cut Tree,C - Maximum Product,E - 组合的输出 题目描述+参考代码+代码讲解——中山大学软件工程学院专选算法课第三次实验 必做题_第2张图片

参考代码 

#include
#include
using namespace std;
#define ll long long

int main(){
    int n;
    int ncase=0;
    while(cin>>n){
        ll ans=0;
        ll num[100];
        for(int i=0;i>num[i];
        }
        for(int i=0;ians)
                    ans=tmp;
            }
        }
        if(ans<0)
            ans=0;
        printf("Case #%d: The maximum product is %lld.\n\n",++ncase,ans);
    }
}

代码讲解

核心是两个for循环,遍历可能的区间。

for(int j=0;i+j

还有一个妙处在 if(ans<0) ans=0;直接把所有可能是负值的情况在最后解决了,不用修改中间的算法来加一些判断。

E - 组合的输出

题目描述

A - Link/Cut Tree,C - Maximum Product,E - 组合的输出 题目描述+参考代码+代码讲解——中山大学软件工程学院专选算法课第三次实验 必做题_第3张图片

参考代码

#include
#include
#include
#include
using namespace std;
bool cmp(vector a,vector b){
  for(int i=0;i>n>>r;
  vector > res;
  for(int i=0;i<(1< tmp;
      for(int j=0;j<=n;j++){
        if(i&(1< a : res){
    for(int b : a){
      cout<

代码讲解

这个真的是对位运算的巧妙应用。

就假设输入是 5 3 吧。

那选3个就是就是要在五个数中选出三个不同的数,在二进制中,就是五位中要有三个一。

遍历2^n,对于一个特定的i,就比如7,就是01011。此时j从0~n-1遍历一遍,就是把i转成2进制的每一位扫一遍,如果该位是1就让cnt+1。

如果cnt=r,说明这个i对应的数刚好是选出的r位数。

此时把这个答案放进一个临时的数组中,tmp.push_back(j+1)把从0开始索引改成从1开始索引。

最后的答案会有C(n,r)个。

i&(1<

i&(1< 是一个位操作,用于检查整数 i 的第 j 位是否为 1。这种操作在组合、子集生成或其他位操作相关的算法中很常见。

我们使用位操作符 &(与操作)来执行这个检查。在这个操作中,我们将数字 1 左移 j 位,从而创建了一个只在第 j 位为 1 的数字(其他位都为 0)。然后,我们使用 & 将此数字与 i 进行比较,如果结果不为 0,则表示 i 的第 j 位为 1,否则该位为 0。

让我们通过一些例子来说明:

  1. 检查数字 i = 5 的第 1 位(从0开始计数,即第二个位):

    • 首先,我们知道 5 在二进制中表示为 101
    • 使用操作 1<<1,我们将数字 1 左移一位得到 10,即 2
    • 现在,我们将 5(即 101)与 2(即 010)进行 & 运算,得到 0。这意味着数字 5 的第 1 位为 0。
  2. 检查数字 i = 5 的第 2 位(从0开始计数,即第三个位):

    • 首先,我们知道 5 在二进制中表示为 101
    • 使用操作 1<<2,我们将数字 1 左移两位得到 100,即 4
    • 现在,我们将 5(即 101)与 4(即 100)进行 & 运算,得到 4。这不是 0,所以数字 5 的第 2 位为 1。

你可能感兴趣的:(算法分析与设计笔记,算法,c++,开发语言)