[NOIP2018提高组]货币系统(动态规划)

猜测结论:\(A\) 去掉其中那些能被其他元素表示的元素即为 \(B\)。样例,3 19 10 6\(19=10+6+3,6=3+3\),就可以去掉,对应的 \(B\) 恰好是 \(\{3,10\}\)

考虑怎样编写程序:因为一个数肯定由比它小的数表示成,所以要进行转移,就要将 \(A\) 从小到大排序。设 \(f_i\) 表示 \(i\) 可以被 \(A\) 中其他元素表示。刷表法,从 \(j-a_i\) 更新到 \(j\),实现时为 \(f_j=f_j \vert f_{j-a_i}\)

下面是 AC 代码:

memset(f,0,sizeof f);//注意清空数组
int n,ans; 
scanf("%d",&n),ans=n;
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
std::sort(a+1,a+n+1);
f[0]=1;
for(int i=1;i<=n;++i)
{
	if(f[a[i]]){ --ans;continue; }//如果能够被表示,就删去
	for(int j=a[i];j<=a[n];++j) f[j]|=f[j-a[i]];//刷表更新后面
}
printf("%d\n",ans);

THE END

posted @ 2021-10-19 16:46  q0000000  阅读(58)  评论(0编辑  收藏  举报