这场比赛是看到孟巨佬一个半小时就AK了,所以我才做的。。。这个题是牛客网这场比赛的卡人题,说实话,有点水。。。看到这个题算了一下复杂度,其实远远达不到背包的o(nm),所以我毫不犹豫的选择了背包,尴尬的是,我的状态写错了。。。贼丢脸。。。
链接:https://www.nowcoder.com/acm/contest/157/F
来源:牛客网
题目描述
小k有一个三轮,它最多可以装105大小的东西
小k有n种商品,他要准备出摊了
每种商品体积为vi,都有105件
输出凑成1~m的体积的总方案数
输出可能会很大,请对大质数19260817取模
输入描述:
第一行两个整数n,m, 接下来n行,每行一个数代表vi
输出描述:
一个数ans表示总方案数
示例1
输入
复制
2 8 1 3
输出
复制
17
说明
从1~m体积的方案数分别为: 1 1 2 2 2 3 3 3
备注:
不要忘记取模!!! n,m,vi <= 50000
题意:一个容量为m的背包,n种物品,每种的数量相对无穷多,问有多少种装法。
思路:一个标准的完全背包取路径数量的问题。关键是常数需要优化。
状态转移方程:![dp[j]=dp[j]+dp[j-v[i]]](https://private.codecogs.com/gif.latex?dp%5Bj%5D%3Ddp%5Bj%5D+dp%5Bj-v%5Bi%5D%5D)
TLE代码:
#include<bits/stdc++.h>
#include<ctime>
using namespace std;
typedef double dl;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long ul;
typedef unsigned long long ull;
const int mod = 19260817;
const int N = 1e6 + 7;
const int M = 1e5 + 7;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
#define mem(a) memset(a,0,sizeof a)
inline ull gcd(unsigned int a,unsigned int b) {return b ? gcd(b,a % b) : a;}
inline ull lcm(unsigned int a,unsigned int b) {return a / gcd(a,b) * b;}
inline double Euler(int n) {return log(n) + 1.0 / (2 * n) + 0.57721566490153286060651209;}
//inline ll inverse_feima(ll n) {return fpow_mod(n,mod - 2);}
ll v[M],dp[M],ans = 0,n,m;
int main()
{
//ios::sync_with_stdio(0);
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
scanf("%lld%lld",&n,&m);
memset(dp,0,sizeof dp);
for(int i = 0;i < n;++i){
scanf("%lld",&v[i]);
dp[v[i]] = 0;
}
dp[0] = 1;
for(int i = 0;i < n;++i)
for(int j = v[i];j <= m;++j){
dp[j] += dp[j - v[i]];
dp[j] %= mod;
}
for(int i = 1;i <= m;++i){
ans += dp[i];
ans %= mod;
}
printf("%lld\n",(ans + mod) % mod);
return 0;
}
由于取模运算很慢,所以对于加法的取模我们可以用条件判断优化。
AC代码:
#include<bits/stdc++.h>
#include<ctime>
using namespace std;
typedef double dl;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long ul;
typedef unsigned long long ull;
const int mod = 19260817;
const int N = 1e6 + 7;
const int M = 1e5 + 7;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
#define mem(a) memset(a,0,sizeof a)
inline ull gcd(unsigned int a,unsigned int b) {return b ? gcd(b,a % b) : a;}
inline ull lcm(unsigned int a,unsigned int b) {return a / gcd(a,b) * b;}
inline double Euler(int n) {return log(n) + 1.0 / (2 * n) + 0.57721566490153286060651209;}
//inline ll inverse_feima(ll n) {return fpow_mod(n,mod - 2);}
ll v[M],dp[M],ans = 0,n,m;
int main()
{
//ios::sync_with_stdio(0);
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
scanf("%lld%lld",&n,&m);
memset(dp,0,sizeof dp);
for(int i = 0;i < n;++i){
scanf("%lld",&v[i]);
dp[v[i]] = 0;
}
dp[0] = 1;
for(int i = 0;i < n;++i)
for(int j = v[i];j <= m;++j){
dp[j] += dp[j - v[i]];
if(dp[j] >= mod) dp[j] -= mod;
}
for(int i = 1;i <= m;++i){
ans += dp[i];
if(ans >= mod) ans -= mod;
}
printf("%lld\n",ans);
return 0;
}