1354 选数字 DP背包 + 数学剪枝

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1354&judgeId=187448

其实这题和在若干个数字中,选取和为val,有多少种不同的选法是一样的。

只不过不能直接枚举背包容量,只能用map的iterate来枚举,这样来加速。

还有一个剪枝就是,所生成的数字要是val的约数,这些才加入去map那里,否则不加。

都是一些没用的状态。

还有这题不能用map的reverse_iterator,会蜜汁wa

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;


#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <hash_map>
using namespace __gnu_cxx;
const int MOD = 1000000007;
map<int, int>dp;
void init() {
    dp.clear();
}
void work() {
    init();
    int n, val;
    scanf("%d%d", &n, &val);
    dp[1] = 1;
    for (int i = 1; i <= n; ++i) {
        int x;
        scanf("%d", &x);
////        if (val % x != 0) continue;
//        for (map<int, int> :: reverse_iterator it = dp.rbegin(); it != dp.rend(); ++it) {
//            if (val / it->first < x) continue;
//            if (val % (it->first * x) != 0) continue;
////            dp[it->first * x] = (dp[it->first * x] + (it->second)) % MOD;
//            dp[it->first * x] += it->second;
//            dp[it->first * x] %= MOD;
//        }
        map<int, int> :: iterator it = dp.end();
        it--;
        for(;; --it) {
            LL t = 1LL * it->first * x;
            if (t <= val && val % t == 0) {
                dp[t] += it->second;
                dp[t] %= MOD;
            }
            if (it == dp.begin()) break;
        }
    }
    printf("%d
", dp[val]);
}

int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    int t;
    scanf("%d", &t);
    while (t--) work();
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/liuweimingcprogram/p/6261830.html