題解/算法 {2597. 美丽子集的数目}

LINK

Solution

审题一定要仔细! 假如我们选出一个子序列 a1, a2, ..., 那么对于任意的ai, aj, 均满足|ai - aj| != K;

一种很简单的算法是: 对数组进行排序, 然后二进制状态枚举, 对于一个数a 判断a - K是否存在, 时间是: (bit_st: 2^20) * (N: 20) ;
看似可以, 但实际上会超时… (而且, 即便你把N: 20 使用Lower_bit 优化为<N, 还是会超时), 只能说 这个题 卡时间卡的比较极限;

@Delimiter

当遇到2^n的二进制枚举时, 应该联想到 DFS递归, 两个算法是完全一样的;
但唯一的区别是: 相比于二进制枚举, DFS递归更有优化/剪枝的空间;
. 比如, 一组方案 (子序列) a, b, c;
. . 如果是二进制枚举 他一定是 比如st = 100101, 然后如果你还需要遍历这个子序列, 那么总时间一定是2^N * N, 没有任何可能去优化;
. . 但如果是DFS递归, 当我们在a b时, 假如他是非法的, 那么我们就不会访问到a b c这种方案, 在a b时 就已经给剪枝掉了;
. . . 换句话说, DFS递归它是: 2^N遍历所有方案 和 N遍历一组方案, 两个过程是结合到一块了 同时进行, 即时间是2^N;

我们同样排序, 然后判断cur - K这个元素是否已经选择;
先看一个错误代码:

void Dfs( int _ind){
    if( _ind >= N){ ++ Ans; return;}
    //--
    int _cur = (* AA)[ _ind];
    //--
    Dfs( _ind + 1); // 不选当前元素
    //--
    if( _cur - BB >= 0 && Cont[ _cur - BB] == 0){ // @Mark_0
        Cont[ _cur] ++;
        Dfs( _ind + 1); // 选当前元素
        //--
        Cont[ _cur] --; // 递归回溯恢复
    }
}

答案是`Ans - 1`

很容易写出这个代码, 而且很难察觉到错误…
举个例子, [1] K=5; 你并不会得到1这个方案, 因为1不符合@Mark_0这个条件;
因此, @Mark_0要改为: if( _cur - BB < 0 || Cont[ _cur - BB] == 0); 这个逻辑一定要搞清楚;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值