• 入门OJ:Coin


    题目描述

    你有n个硬币,第i硬币面值为ai,现在总队长想知道如果丢掉了某个硬币,剩下的硬币能组成多少种价值?(0价值不算)

    输入格式

    第一行一个整数n

    第二行n个整数。,a1,a2…an。

    1<=n<=100,1<=ai<=3000

    输出格式

    输出n行

    第i行表示没有第i个硬币能组成多少种价值。


    显然是个背包题,代价设计为硬币面值,价值设计为有几种方案组成当前面值。

    那么设dp(i,j)表示前i个硬币有几种方案组成价值j,可以得出转移方程:

    [if(j>=val[i])dp[i][j]+=dp[i-1][j-val[i]]\ else:dp[i][j]=dp[i-1][j] ]

    压成一维之后:

    [dp[j]+=dp[j-val[i]];val[i]≤j≤m ]

    那么我们发现每一位的j可以由若干个状态更新过来。根据加法交换律,某个编号为i的硬币更新j状态的dp(j-val(i))先加后加都无所谓。根据这一点,我们可以认为任意一个硬币是最后被加进去的。

    结合我们的结论和题目,当我们丢掉了一个硬币之后就相当于撤销这个硬币对dp数组的贡献。我们可以认为它是最后被更新上去的,所以我们只需要把更新的操作反着执行一遍即可:

    for(register int j=val[i];j<=m;j++) dp[j]-=dp[j-val[i]];
    

    然后我们的答案是能凑出的价值的个数,只需要枚举求一下有那些价值可以被≥1种方案凑出即可。

    时间复杂度为O(NM)。

    * dp数组在计算中会爆longlong,记得开高精。或者int128

    * c数组可以直接用一个变量sum代替

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define maxn 101
    #define maxm 300001
    using namespace std;
    
    __int128 dp[maxm];
    int n,m,val[maxn],c[maxm];
    
    inline int read(){
    	register int x(0),f(1); register char c(getchar());
    	while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
    	while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    	return x*f;
    }
    
    inline void update(){
    	for(register int i=1;i<=m;i++) c[i]=c[i-1]+(dp[i]>0);
    }
    inline void add(const int &val){
    	for(register int i=m;i>=val;i--) dp[i]+=dp[i-val];
    }
    inline void del(const int &val){
    	for(register int i=val;i<=m;i++) dp[i]-=dp[i-val];
    }
    
    int main(){
    	n=read(),dp[0]=1;
    	for(register int i=1;i<=n;i++) val[i]=read(),m+=val[i];
        for(register int i=1;i<=n;i++) add(val[i]);
        for(register int i=1;i<=n;i++){
            del(val[i]),update(),printf("%d
    ",c[m]),add(val[i]);
        }
    	return 0;
    }
    
  • 相关阅读:
    RocketMQ简介
    redis简介
    netcat
    NOI2018 归程
    图论小专题B
    CF558E A Simple Task
    图论小专题A
    初等网络流初步
    2019炎德杯知识能力竞赛 游记
    POJ2176 Folding
  • 原文地址:https://www.cnblogs.com/akura/p/11005973.html
Copyright © 2020-2023  润新知