Backward Digit Sums G/S

链接

这题需要结合两个知识,一个是输出全排列,另一个是求出杨辉三角的某一行

二者并不难,唯一的难点是超时问题,题目最大是12

而12!非常大,因此我们需要采取一些策略减少遍历次数,也就是剪枝

我们看题目的输入样例 4 16 也就是说我们需要找到合适的排列,使

1 2 3 4

1 3 3 1(杨辉三角)

两个数组对应元素相乘等于16

当我们确定第一个数字为1的时候,当前总和为1x1=1,我们可以思考,如果当前和加上剩下的最大可能和都小于16或者当前和加上最小可能和大于16的时候,就证明1放在第一个数是不正确的

最大可能和直观来讲就是大数乘大数,也就是1+2x1+3x3+4x3=24<16

而最小可能和则相反,就是1+2x3+3x3+4x1=20>16

我们发现,当1放在第一位时,最小可能和都大于16,那么其他的可能和就都大于16了,所以这种情况直接忽略不管

那么,最大可能和真的是那么求的吗,是的

根据排序不等式顺序和>乱序和>倒序和,可知,我们的只管感觉没错

回到题目,1不能放在第一位,那么2可以吗?不行,最小可能和为18,依旧超过

依次类推,我们可以得到最终答案为3 1 4 2(题目要求字典序最小的结果输出,所以是这个答案)

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
void dfs(int pos, int currentSum, int n, int m,
    vector<int>& weights, vector<int>& ans,
    vector<bool>& used, bool& found) {
    if (found) return;
    // 剪枝:如果当前和已经超过目标值
    if (currentSum > m) return;
    int max_value = currentSum, min_value = currentSum;
    vector<int>residual;
    vector<int>res;
    for (int i = 0;i < n;i++) {
        if (!used[i]) {
            residual.push_back(i + 1);
        }
    }
    for (int i = pos;i < n;i++) {
        res.push_back(weights[i]);
    }
    sort(residual.begin(), residual.end());
    sort(res.begin(), res.end());
    for (int i = 0;i < res.size();i++) {
        max_value += res[i] * residual[i];
        min_value += res[i] * residual[res.size() - i - 1];
    }
    if (max_value < m) return;
    if (min_value > m) return;
    if (pos == n) {
        if (currentSum == m) { 
            found = true;
            for (int i = 0; i < n; i++) {
                cout << ans[i];
                if (i < n - 1) cout << " ";
            }
        }
        return;
    }
    for (int i = 0; i < n; i++) {
        if (!used[i]) {
            used[i] = true;
            ans[pos] = i + 1;
            dfs(pos + 1, currentSum + (i + 1) * weights[pos],
                n, m, weights, ans, used, found);
            if (found) return;
            used[i] = false;
        }
    }
}

int main() {
    int n, m;
    cin >> n >> m;
    vector<int> weights(n);
    weights[0] = 1;
    for (int i = 1; i < n; i++) {
        weights[i] = weights[i - 1] * (n - i) / i;
    }

    vector<int> ans(n);
    vector<bool> used(n, false);
    bool found = false;

    dfs(0, 0, n, m, weights, ans, used, found);

    return 0;
}

时间复杂度:好吧,我也算不来

空间复杂度:O(n)

全部评论

相关推荐

2025-12-15 17:56
商洛学院 运维工程师
点赞 评论 收藏
分享
2025-12-13 14:51
已编辑
井冈山大学 算法工程师
龙虾x:算法比你强的没有你美,比你美的…..算了已经没有比你美的了
工作两年想退休了
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务