HELLLLLLLLLP!!

题目描述

有n种面值的硬币A1,A2…An, 每种硬币有C1,C2…Cn个
求他们一共可以组合成多少种1−m之间面值

输入格式

第一行输入两个整数n,m
第二行输入2∗n个整数,A1,A2…An,C1,C2…Cn

输出格式

输出一个整数

样例

Input 1

3 10 1 2 4 2 1 1

Output 1

8

数据范围

1<=n<=100,1<=m<=105
1<=Ai<=105,1<=Ci<=1000

样例解释

样例解释:
硬币面值为1,2,4,数量分别为2,1,1
可以组成的面值为1,2,4,3,5,6,7,8共8种

我哪里错了 :broken_heart:
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int a[N],dp[N];
int main(){
int n,m;
scanf(“%d”,&n);
for(int i=1;i<=n;i++){
scanf(“%d”,&a[i]);
m+=a[i];
}dp[0]=1;
for(int i=1;i<=n;i++){
for(int j=m;j>=a[i];j–){
if(dp[j-a[i]]==1) dp[j]=1;
}
}int ret=0;
for(int i=1;i<=m;i++){
ret+=dp[i];
}printf(“%d”,ret);
return 0;
}

2 个赞

选中你的代码
再点击</>
可以格式化你的代码
让你的代码更美观

3 个赞

思路:
这是简单的完全背包
但是计算一下

传统的完全背包无法通过时间复杂度,

所以我们增加优化
如果状态dp[j]已经可以被满足则不再枚举,直接进行下一个状态
代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,dp[1000050],book[1000050];
struct edge
{
    int a,c;
}p[1050];
signed main()
{
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++)scanf("%lld",&p[i].a);
    for(int i=1;i<=n;i++)scanf("%lld",&p[i].c);
    dp[0]=1;
    book[0]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=m;j>=1;j--)
        {
            if(book[j])continue;
            for(int k=1;k*p[i].a<=j&&k<=p[i].c;k++)
            {
                dp[j]|=dp[j-k*p[i].a];
                if(dp[j])book[j]=1;
            }
        }
    }
    int ans=0;
    for(int i=1;i<=m;i++)
        if(dp[i])++ans;
    printf("%lld",ans);
    return 0;
}

至少样例过力(喜

3 个赞

有用的话给个解决方案

3 个赞

Thanks

1 个赞

@陈俊屹 你。。。。。。

1 个赞

我问题目啊

1 个赞

有问题吗

没问题吗

你说哪里有问题

交流代码答案,你觉得行吗

论坛上多的是吧

而且对你有什么害处

啊这。。。。你牛

我又没抄

那你有意思嘛

我自己觉得有意思行了吧