【题解】P1021 邮票面值设计
题面
前言
莫名其妙卡了云落两个点……
正文
嗯,这种自己构造方案的操作很难不想到搜索
问题是爆搜肯定是没有前途滴!
如果邮票的种类没有用完,就在可能的搜索范围内进行下一步拓展
我们记当前要确定第 \(x\) 种邮票,边界条件为 \(x==k+1\)
如果没有到边界条件,那么就依据范围拓展
范围是 \([a_{x-1}+1,当前最大面值+1]\)
否则就求当前最大面值
显然我们需要维护一个操作,统计当前最大面值
这个显然可以用 DP 维护
具体地,这是一个完全背包
设 \(dp_i\) 表示面值组成 \([1,i]\) 最少的邮票花费数目
转移方程:\(dp_i = \mathop{min}\limits_{j = a_i}^{a_{x} \times n}
\lbrace dp_{j - a_i} + 1 \rbrace\)
然后就无了……
代码
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=5e4+10,inf=2147483647;
int n,k,a[maxn],b[maxn],dp[maxn],ans;
inline int DP(int x){
for(int i=1;i<maxn;i++){
dp[i]=inf;
}
dp[0]=0;
for(int i=1;i<=x;i++){
for(int j=a[i];j<=a[x]*n;j++){
if(dp[j-a[i]]<n){
dp[j]=min(dp[j],dp[j-a[i]]+1);
}
}
}
int res=0;
while(dp[res+1]<=100){
res++;
}
return res;
}
inline void dfs(int x){
if(x==k+1){
for(int i=1;i<maxn;i++){
dp[i]=inf;
}
int res=DP(x-1);
if(res>ans){
for(int i=1;i<=k;i++){
b[i]=a[i];
ans=res;
}
}
return;
}
int mx=DP(x-1);
for(int i=a[x-1]+1;i<=mx+1;i++){
a[x]=i;
dfs(x+1);
a[x]=0;
}
return;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>k;
a[1]=1;
dfs(2);
for(int i=1;i<=k;i++){
cout<<b[i]<<' ';
}
cout<<endl<<"MAX="<<ans<<endl;
return 0;
}
后记
nyn 学姐好巨啊
完结撒花!