zoukankan      html  css  js  c++  java
  • bzoj3312

    K个硬币,要买N个物品。

    给定买的顺序,即按顺序必须是一路买过去,当选定买的东西物品序列后,付出钱后,货主是不会找零钱的。现希望买完所需要的东西后,留下的钱越多越好,如果不能完成购买任务,输出-1

    $$k leq 16 N leq 100000$$

    考虑状压dp

    $dp[STATE]$表示状态为$STATE$的时候能买的最多的东西

    记一下最大值 二分一下

    。。

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=5e5+5;
    typedef long long LL;
    inline LL read()
    {
        LL x = 0,f = 1;
        char ch;
        for(ch=getchar();!isdigit(ch);ch=getchar())if(ch == '-')f = -f;
        for(;isdigit(ch);ch=getchar())x = 10*x+ch-'0';
        return x*f;
    }
    int k,n;
    LL dp[maxn],a[maxn],sum[maxn],MAXSTATE,ans;
    inline LL find(LL l,LL r,LL x)
    {
        LL l1=l,ret=0,top=sum[x]-sum[x-1];
        while(l<=r)
        {
            LL mid=(l+r)/2;
            if (a[mid]-a[l1-1]<=top)ret=mid,l=mid+1;
            else r=mid-1; 
        }
        return ret;
    }
    int main()
    {
        scanf("%d%d",&k,&n);
        for(int i=1;i<=k;i++)sum[i] = sum[i-1] + read();
        for(int i=1;i<=n;i++)a[i]=read()+a[i-1];
        MAXSTATE=(1<<k)-1;ans=2147483233;
        for(int i=0;i<=MAXSTATE-1;i++)
        {
            for(int j=1;j<=k;j++)
                if(!(i&(1<<j-1)))
                {
                    LL num=find(dp[i]+1,n,j);
                    dp[i|(1<<j-1)]=max(dp[i|(1<<j-1)],num);
                    if(num==n)
                    {
                        LL tem=0;
                        for(int l=1;l<=k;l++)
                            if((i|(1<<j-1))&(1<<l-1))tem+=sum[l]-sum[l-1];
                        ans=min(ans,tem);
                    }
                }
        }
        printf(ans == 2147483233 ? "-1" : "%d" , sum[k]-ans);
    }
    View Code
  • 相关阅读:
    CodeForces 687B Remainders Game
    CodeForces 689D Friends and Subsequences
    CSU 1810 Reverse
    生成树收录
    吃奶酪
    带逆向思维的并查集
    中位数定理
    种类并查集(关押犯人)
    带权并查集
    分层图
  • 原文地址:https://www.cnblogs.com/Kong-Ruo/p/8611848.html
Copyright © 2011-2022 走看看