zoukankan      html  css  js  c++  java
  • 入门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;
    }
    
  • 相关阅读:
    外校培训前三节课知识集合纲要(我才不会告诉你我前两节只是单纯的忘了)
    floyd算法----牛栏
    bfs开始--马的遍历
    (DP 线性DP 递推) leetcode 64. Minimum Path Sum
    (DP 线性DP 递推) leetcode 63. Unique Paths II
    (DP 线性DP 递推) leetcode 62. Unique Paths
    (DP 背包) leetcode 198. House Robber
    (贪心 复习) leetcode 1007. Minimum Domino Rotations For Equal Row
    (贪心) leetcode 452. Minimum Number of Arrows to Burst Balloons
    (字符串 栈) leetcode 921. Minimum Add to Make Parentheses Valid
  • 原文地址:https://www.cnblogs.com/akura/p/11005973.html
Copyright © 2011-2022 走看看