Loading

NOIP 模拟 $29\; \rm 完全背包问题$

题解 \(by\;zj\varphi\)

一道 \(\rm dp\) 题。

现将所有种类从小到大排序,然后判断,若最小的已经大于了 \(\rm l\),那么直接就是一个裸的完全背包,因为选的总数量有限制。

\(\rm f_{i,j,k}\) 为选了前 \(\rm i\) 种物品,总数为 \(\rm j\),容量为 \(\rm k\),是否可行,转移很简单。

对于另一种情况,能构造出的最小差距就是 \(v_1\),那么只要记录一下模 \(\rm v_1\) 的值即可。

\(\rm f_{i,j}\) 为选了 \(\rm i\) 个有限制的物品,模数为 \(j\) 的状态下最小和为多少,则有转移方程:

\[\rm f_{i,j}=\min(f_{i,j},f_{i,(j-v_i)mod\;v_1}+v_i)\;\; v_i<l\\ f_{i,j}=\min(f_{i,j},f_{i-1,(j-v_i)mod\;v_1}+v_i)\;\; v_i\ge l \]

发现这个转移会出现环,所以直接最短路。

#include<bits/stdc++.h>
#define ri register signed
#define p(i) ++i
namespace IO{
    char buf[1<<21],*p1=buf,*p2=buf;
    #define gc() p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?(-1):*p1++
    struct nanfeng_stream{
        template<typename T>inline nanfeng_stream &operator>>(T &x) {
            ri f=0;x=0;register char ch=gc();
            while(!isdigit(ch)) {f|=ch=='-';ch=gc();}
            while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
            return x=f?-x:x,*this;
        }
    }cin;
}
using IO::cin;
namespace nanfeng{
    #define node(nm,v,dis) (node){nm,v,dis}
    #define FI FILE *IN
    #define FO FILE *OUT
    template<typename T>inline T cmax(T x,T y) {return x>y?x:y;}
    template<typename T>inline T cmin(T x,T y) {return x>y?y:x;}
    typedef long long ll;
    static const int N=51,M=3e5+7,C=31,V=1e4+7;
    int v[N],n,m,l,c;
    bool vis[C][V];
    ll dis[C][V];
    struct node{int nm,v;ll dis;};
    std::queue<node> que;
    std::bitset<M> f[N][C];
    inline void spfa() {
        memset(dis,127,sizeof(dis));
        dis[0][0]=0;
        que.push(node(0,0,0));
        while(!que.empty()) {
            node nw=que.front();que.pop();
            vis[nw.nm][nw.v]=0;
            for (ri i(2);i<=n;p(i)) {
                int tmp;
                if (v[i]<l) {
                    if (dis[nw.nm][tmp=(nw.v+v[i])%v[1]]>nw.dis+v[i]) {
                        dis[nw.nm][tmp]=nw.dis+v[i];
                        if (!vis[nw.nm][tmp]) que.push(node(nw.nm,tmp,nw.dis+v[i])),vis[nw.nm][tmp]=1; 
                    }
                } else if (nw.nm<c) {
                    if (dis[nw.nm+1][tmp=(nw.v+v[i])%v[1]]>nw.dis+v[i]) {
                        dis[nw.nm+1][tmp]=nw.dis+v[i];
                        if (!vis[nw.nm+1][tmp]) que.push(node(nw.nm+1,tmp,nw.dis+v[i])),vis[nw.nm+1][tmp]=1;
                    }
                }
            }
        }
    }
    inline int main() {
        //FI=freopen("nanfeng.in","r",stdin);
        //FO=freopen("nanfeng.out","w",stdout);
        cin >> n >> m;
        for (ri i(1);i<=n;p(i)) cin >> v[i];
        cin >> l >> c;
        std::sort(v+1,v+n+1);
        if (v[1]>=l) {
            f[0][0][0]=1;
            for (ri i(1);i<=n;p(i)) {
                for (ri j(0);j<=c;p(j)) {
                    f[i][j]=f[i-1][j];
                    if (j) f[i][j]|=f[i][j-1]<<v[i];
                }
            }
            for (ri i(0);i<c;p(i)) f[n][c]|=f[n][i];
            for (ri i(1);i<=m;p(i)) {
                ll w;cin >> w;
                if (w>=M) puts("No");
                else printf("%s\n",f[n][c][w]?"Yes":"No");
            }
        } else if (v[1]<l) {
            spfa();
            for (ri i(0);i<c;p(i))
                for (ri j(0);j<v[1];p(j)) dis[c][j]=cmin(dis[c][j],dis[i][j]);
            for (ri i(1);i<=m;p(i)) {
                ll w;cin >> w;
                printf("%s\n",w>=dis[c][w%v[1]]?"Yes":"No");
            }
        }
        return 0;
    }
}
int main() {return nanfeng::main();}\
posted @ 2021-08-06 20:54  ナンカエデ  阅读(48)  评论(0编辑  收藏  举报