• 找钱 [动态规划, 背包]


    找钱



    color{grey}{最初想法}

    最后一条限制不好处理, 于是关于 小 LL 的 背包信息 搜出来, 售货员 的背包信息 dpdp,
    但是忘记 记忆化 了, 丢了 50pts50pts

    505ms505 ms AC 代码 downarrow

    #include<bits/stdc++.h>
    #define reg register
    
    int read(){
            char c;
            int s = 0, flag = 1;
            while((c=getchar()) && !isdigit(c))
                    if(c == '-'){ flag = -1, c = getchar(); break ; }
            while(isdigit(c)) s = s*10 + c-'0', c = getchar();
            return s * flag;
    }
    
    const int maxn = 1000006;
    const int mod = 1e9 + 7;
    
    int N;
    int X;
    int Ans;
    int F2[maxn];
    int F3[maxn];
    int F4[1005][20005];
    
    struct Node{ int a, b, c; } A[maxn];
    
    int DFS(int k, int s){
            if(k == N+1){ if(s < X) return 0; return F2[s - X]; }
            if(~F4[k][s]) return F4[k][s];
            int res = 0;
            for(reg int i = 1; i <= A[k].b; i ++){
                    int ns = s + A[k].a*i;
                    if(ns - X >= A[k].a) break ;
                    res += DFS(k+1, ns); res %= mod;
            }
            res += DFS(k+1, s); res %= mod;
            return F4[k][s] = res;
    }
    
    int main(){
            N = read(), X = read();
            for(reg int i = 1; i <= N; i ++) A[i].a = read(), A[i].b = read(), A[i].c = read();
            std::reverse(A+1, A+N+1); F2[0] = 1;
            for(reg int i = 1; i <= N; i ++){
                    for(reg int j = 0; j <= X; j ++) F3[j] = F2[j];
                    for(reg int k = 1; k <= A[i].c; k <<= 1){
                            for(reg int j = X; j >= k*A[i].a; j --) F2[j] = (F2[j] + F3[j-k*A[i].a]) % mod;
                            A[i].c -= k;
                    }
                    if(A[i].c > 0) 
                            for(reg int j = X; j >= A[i].c*A[i].a; j --) F2[j] = (F2[j] + F3[j-A[i].c*A[i].a]) % mod;
            }
            memset(F4, -1, sizeof F4);
            printf("%d
    ", DFS(1, 0));
            return 0;
    }
    

    color{red}{正解部分}

    F1[x]F_1[x] 表示 小 LL 凑出 xx 的方案数, F2[x]F_2[x] 表示 售货员 凑出 xx 的方案数,

    但是题目中对 小 LL 的钱数 有限制, 于是先使用 完全背包 更新一遍 F1[x]F_1[x],

    然后 F1[x]F_1[x] 减去 F1[xai×(bi+1)]F_1[x - a_i imes (b_i + 1)] 得到 满足 物品个数限制 .

    状态转移时 限制上界X+ai1X+a_i-1倒序循环 满足 纸币面值限制 .


    color{red}{实现部分}

    #include<bits/stdc++.h>
    #define reg register
    
    int read(){
            char c;
            int s = 0, flag = 1;
            while((c=getchar()) && !isdigit(c))
                    if(c == '-'){ flag = -1, c = getchar(); break ; }
            while(isdigit(c)) s = s*10 + c-'0', c = getchar();
            return s * flag;
    }
    
    const int maxn = 1000006;
    const int mod = 1e9 + 7;
    
    int N;
    int X;
    int Ans;
    int a[maxn];
    int b[maxn];
    int c[maxn];
    int F1[maxn];
    int F2[maxn];
    
    int main(){
            N = read(), X = read();
            for(reg int i = 1; i <= N; i ++) a[i] = read(), b[i] = read(), c[i] = read();
            F1[0] = F2[0] = 1;
            for(reg int i = N; i >= 1; i --){
                    for(reg int j = a[i]; j < X+a[i]; j ++) F1[j] = (F1[j] + F1[j-a[i]]) % mod;
                    for(reg int j = X+a[i]-1; j >= a[i]*(b[i]+1); j --) F1[j] = (F1[j] - F1[j-a[i]*(b[i]+1)] + mod) % mod;
                    for(reg int j = a[i]; j < X<<1; j ++) F2[j] = (F2[j] + F2[j-a[i]]) % mod;
                    for(reg int j = 2*X-1; j >= a[i]*(c[i]+1); j --) F2[j] = (F2[j] - F2[j-a[i]*(c[i]+1)] + mod) % mod;
            }
            for(reg int y = X; y <= 2*X-1; y ++) Ans = (Ans + 1ll*F1[y]*F2[y-X]%mod) % mod;
            printf("%d
    ", Ans);
            return 0;
    }
    
  • 相关阅读:
    单行居中,2行居左,超过2行省略
    Angular2环境搭建
    数字保留2位小数
    结束循环函数
    获取元素的定位值
    $.extend
    node使用指南
    Telsa显卡比较
    Jupyter-notebook 不自动打开浏览器解决办法
    teamviewer连接未就绪的解决(Manjaro Linux)
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822423.html
Copyright © 2020-2023  润新知