zoukankan      html  css  js  c++  java
  • USACO13NOV No Change G

    题目链接

    Solution

    状压 dp 题:状态 (S) 一共有 (k) 位,表示当前硬币是否已经用过了。设 (f_S) 表示状态为 (S) 时最多能购买多少物品。

    考虑把 (S) 中的一个 (0) 变成 (1):需要使用当前硬币,从 (f_S) 开始购买尽可能多的物品。为了保证效率,这一过程可以用前缀和 + 二分查找来维护。如果所有硬币都用完后购买不到 (n) 个物品,输出无解;否则,设 (num_S) 表示状态 (S) 使用了多少金币,答案为所有 (f_S=n)(num_S) 的最小值。

    Code

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
     
    const int N = 2000000;
    int n, k, max_ = 0, a[100], num[N], b[N], f[N], sum[N];
     
    int check(int x, int y)
    {
        int l = x, r = n;
        while(l + 1 < r)
        {
            int mid = (l + r) / 2;
            if(sum[mid] - sum[x] > y) r = mid;
            else l = mid;
        }
        if(sum[r] - sum[x] <= y) return r;
        return l;
    }
     
    int main()
    {
        scanf("%d%d", &k, &n);
        for(int i = 1; i <= k; i++) scanf("%d", &a[i]);
        for(int i = 1; i <= n; i++) scanf("%d", &b[i]), sum[i] = sum[i - 1] + b[i];
        memset(f, 0, sizeof(f));
        for(int i = 0; i < (1 << k); i++)
            for(int j = 1; j <= k; j++)
            {
                if((i & (1 << (j - 1))) != 0) continue;
                num[i] += a[j];
                f[i | (1 << (j - 1))] = max(f[i | (1 << (j - 1))], check(f[i], a[j]));
            }
        if(f[(1 << k) - 1] < n) { printf("-1"); return 0; }
        for(int i = 0; i < (1 << k); i++) if(f[i] == n) max_ = max(max_, num[i]);
        printf("%d", max_);
        return 0;
    } 
    
  • 相关阅读:
    window常见事件onload
    BOM顶级对象window
    模拟京东快递单号查询案例
    [Hibernate] one-to-one
    Katy Perry
    [Java] int 转换为BigDecimal
    [easyUI] datagrid 数据格 可以进行分页
    [easyUI] 树形菜单 tree
    [easyUI] lazyload 懒加载
    [easyUI] autocomplete 简单自动完成以及ajax从服务器端完成
  • 原文地址:https://www.cnblogs.com/Andy-park/p/12493994.html
Copyright © 2011-2022 走看看