“DP是一枚小小的邮票,我在这头,AC在那头。”
(撸完大合集来看这两张图,再次体会被DP支配的恐惧┗( 0﹏0 )┛)
一、贴邮票问题(侧重递推)
1.难度系数:渣渣肥
【问题描述】
有 n 种不同面额的邮票,每种只有1张。
问题1、计算用这些邮票能贴出面额S的方案数。
问题2、计算用这些邮票能贴出多少种不同的面额。
【输入格式】
第 1 行:两个整数 n 和 S,表示有 n 种邮票,要贴出面额 S。
第 2 行:有 n 个整数,表示每种邮票的面额a[i]。
【输出格式】
包含两行:第一行为问题1的答案 mod 12345的结果,第二行为问题2的答案。
【输入样例】
3 4
1 3 4
【输出样例】
2
6
【样例解释】
有3张张邮票,面额分别为:1、3、4
贴出面额4有两种方案:1+4=4或4。
可贴出6种面额:1、3、1+3=4、1+4=5、2+4、1++3+4=7。
【数据范围】
1 <= N <= 100;
1 <= K <= 20000;
每种邮票面额不超过2000。
#include<algorithm>
#include<iostream>
#include<fstream>
#include<cstdio>
#define MAXn 105
#define MAXs 200005
using namespace std;
int a[MAXn],f[MAXs]={0},book[MAXs]={0};
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
int N,S,tot=0;
scanf("%d%d",&N,&S);
for(int i=1;i<=N;i++){
scanf("%d",&a[i]);
tot+=a[i];
}
f[0]=1;book[0]=1;//注意初始化边界
for(int n=1;n<=N;n++){
for(int s=tot;s>=a[n];s--){//降维,倒着枚举
f[s]+=f[s-a[n]];
if(book[s-a[n]]>0) book[s]=1;//前面的f[s]可能模成0,选标记数组作参考
f[s]%=12345;
}
}
int cnt=0;
for(int i=1;i<=tot;i++) cnt+=book[i];
printf("%d\n%d",f[S],cnt);
return 0;
}
2.难度系数:混合渣渣肥
【问题描述】
问题1:有 N 种不同面额的邮票,第i种有p[i]张。问:用这些邮票能贴出多少种不同的面额和贴出面额 K 的方案数。
问题2:有 N 种不同面额的邮票,每种邮票有无限多张。问:可以贴出多少种不同的不大于 K 面额和贴出面额 K 的方案数。
【输入格式】
第 1 行:两个整数 N 和 K,表示有N种邮票,要贴出面额 K。
第 2 行:有N个整数,表示有N种邮票的面额a[i]。
第 3 行:有N个整数,表示有N种邮票的张数量p[i](针对问题1)。
【输出格式】
三行:
第 1 行:对应问题1,两个整数,表示不同的邮票面额和贴出面额 K 的方案数mod 12345。
第 2 行:对应问题2,两个整数,表示不同的邮票面额和贴出面额 K 的方案数mod 12345。
【输入样例】
3 4
1 3 4
2 1 3
【输出样例】
17 2
4 3
【数据范围】
1 <= N <= 100;
1 <= K <= 20000
p[1]+p[2]+…+p[N] <= 500;
每种邮票面额不超过200。
#include<algorithm>
#include<iostream>
#include<fstream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#define MAXn 105
#define MAXs 200005
using namespace std;
int a[MAXn],p[MAXn];
int f[MAXs]={0},book[MAXs]={0};
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
int N,S,tot=0;
scanf("%d%d",&N,&S);
for(int i=1;i<=N;i++) scanf("%d",&a[i]);
for(int i=1;i<=N;i++){
scanf("%d",&p[i]);
tot+=a[i]*p[i];
}
//Problem 1:
f[0]=1;book[0]=1;//注意初始化边界
for(int n=1;n<=N;n++){
for(int s=tot;s>=0;s--){//降维,倒着枚举
for(int m=1;m<=p[n];m++){//m不从0开始,否则会改动f[0]的值
if(s>=a[n]*m){
f[s]+=f[s-a[n]*m];
if(book[s-a[n]*m]>0) book[s]=1;//前面的f[s]可能模成0,选标记数组作参考
f[s]%=12345;
}
}
}
}
int cnt=0;
for(int i=1;i<=tot;i++) cnt+=book[i];
printf("%d %d\n",cnt,f[S]);
//Problem 2:
memset(f,0,sizeof(f));
memset(book,0,sizeof(book));
f[0]=1;book[0]=1;//