博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
bzoj1042硬币购物
阅读量:7236 次
发布时间:2019-06-29

本文共 3700 字,大约阅读时间需要 12 分钟。

题目:

dp预处理+容斥原理。

先预处理求出无限制的各面值的组成方案数 f (完全背包)。

求s [ i ]有限制的,就是s [ i ]无限制方案数 - 单种硬币一定超过限制的方案数 + 两种的 - 三种的 + 四种的。

第 k 中硬币一定超过限制的方案数就是f [ s [ i ] - c [ k ] * ( d [ k ] + 1 ) ],即确定用了 d + 1 个该硬币,刨去它们后的无限制方案数。

当 c [ k ] * ( d [ k ] + 1 ) > s [ i ] 时不用操作,即没有“超过该限制”的可能。但== s [ i ] 时还是要操作的,f [ 0 ] = 1。

以为要用高精度,结果WA。看看题解发现不用高精度,于是……

如果高精度的话,防止某次减到了负数,可以先把加的弄了(反正只有四种硬币)。

非高精AC代码:

#include
#include
using namespace std;typedef long long ll;ll c[5],d[1005][5],tot,mx,s[1005],f[100005],ans;void pre(){ f[0]=1;/// for(int i=1;i<=4;i++) for(ll j=c[i];j<=mx;j++) f[j]+=f[j-c[i]];}void dfs(ll now,ll k,ll cnt,ll z)//第now次询问,第k号,选了cnt个,f目前脚标 { if(z<0)return;//不是z<=0!! if(k==5) { if(cnt&1)ans-=f[z]; else if(cnt)ans+=f[z]; return; } dfs(now,k+1,cnt,z); dfs(now,k+1,cnt+1,z-c[k]*d[now][k]-c[k]);}int main(){ for(int i=1;i<=4;i++)scanf("%lld",&c[i]); scanf("%lld",&tot); for(int i=1;i<=tot;i++) scanf("%lld%lld%lld%lld%lld",&d[i][1],&d[i][2],&d[i][3],&d[i][4],&s[i]),mx=max(mx,s[i]); pre(); for(int i=1;i<=tot;i++) { ans=f[s[i]]; dfs(i,1,0,s[i]); printf("%lld\n",ans); } return 0;}

高精WA代码:

#include
#include
#include
using namespace std;typedef long long ll;const int INF=100005;ll c[5],d[1005][5],tot,s[1005],mx,tp;int f[INF][205],ans[205];void plu(ll k,int a[],int b[]){ int tmp[205]={
0},lm=max(a[0],b[0]); for(int i=1;i<=lm;i++) { tmp[i]+=a[i]+b[i]; if(tmp[i]>10)tmp[i]-=10,tmp[i+1]++; } tmp[0]=lm; if(tmp[tmp[0]+1])tmp[0]++; memcpy(f[k],tmp,sizeof tmp);}void pre(){ f[0][1]=1;f[0][0]=1; for(int i=1;i<=4;i++) for(ll j=c[i];j<=mx;j++) plu(j,f[j],f[j-c[i]]);}void print(){// printf("(%d)",ans[0]); for(int i=ans[0];i;i--) printf("%d",ans[i]); printf("\n");}void plu2(ll k){ int lm=max(ans[0],f[k][0]); for(int i=1;i<=lm;i++) { ans[i]+=f[k][i]; if(ans[i]>10)ans[i]-=10,ans[i+1]++; } if(ans[ans[0]+1])ans[0]++;// printf("++ k=%d ",k);print();}void jian(ll k){// int lm=max(ans[0],f[k][0]); for(int i=1;i<=f[k][0];i++) { ans[i]-=f[k][i]; if(ans[i]<0)ans[i]+=10,ans[i+1]--; } while(!ans[ans[0]]&&ans[0]>1)ans[0]--;// printf("-- k=%d ",k);print();}//void debugprint()//{// for(int i=1;i<=s[1];i++)// {// printf("i=%d ",i);// for(int j=f[i][0];j;j--)// printf("%d",f[i][j]);// printf("\n");// }//}int main(){ for(int i=1;i<=4;i++)scanf("%lld",&c[i]); scanf("%lld",&tot); for(int i=1;i<=tot;i++) { scanf("%lld%lld%lld%lld%lld",&d[i][1],&d[i][2],&d[i][3],&d[i][4],&s[i]); mx=max(mx,s[i]); } pre(); for(int i=1;i<=tot;i++) { memcpy(ans,f[s[i]],sizeof f[s[i]]);//// debugprint(); for(int u=1;u<4;u++) for(int v=u+1;v<=4;v++) { tp=c[u]*d[i][u]+c[v]*d[i][v]+c[u]+c[v]; if(tp<=s[i])plu2(s[i]-tp); ///<=!!!,因为我的f[0]有值为1 ;正是要用这个1! } tp=c[1]*d[i][1]+c[2]*d[i][2]+c[3]*d[i][3]+c[4]*d[i][4]+c[1]+c[2]+c[3]+c[4]; if(tp<=s[i])plu2(s[i]-tp); for(int u=1;u<=4;u++) { tp=c[u]*d[i][u]+c[u]; if(tp<=s[i])jian(s[i]-tp); } for(int u=1;u<=2;u++) for(int v=u+1;v<=3;v++) for(int j=v+1;j<=4;j++) { tp=c[u]*d[i][u]+c[v]*d[i][v]+c[j]*d[i][j]+c[u]+c[v]+c[j]; if(tp<=s[i])jian(s[i]-tp); } print(); } return 0;}

 

转载于:https://www.cnblogs.com/Narh/p/8531238.html

你可能感兴趣的文章
使用zabbix discovery监控网卡百兆
查看>>
mysql连接小错误一例
查看>>
Flash持续集成自动化单元测试
查看>>
oracle一点资料
查看>>
28个实用的源码/文档比较合并工具
查看>>
js的cookie操作
查看>>
Nginx 域名跳转配置
查看>>
ASP.NET MVC扩展库
查看>>
pyodbc简单使用
查看>>
数据库厂商提供的 Providers for ASP.NET
查看>>
memcached演练(5) 内存管理
查看>>
烂泥:Windows server 2008开启远程桌面
查看>>
烂泥:IE10浏览器兼容模式
查看>>
我的家庭私有云计划-21
查看>>
Windows10-加速在企业中的部署
查看>>
综合应用WPF/WCF/WF/LINQ之三十八:实现一个简单的DataGrid之总体介绍
查看>>
Variant类型在各语言中的参数传递
查看>>
Exchange server 2003迁移到2010之升级默认地址簿及地址策略
查看>>
网站及监控利器 Pandora FMS使用体验
查看>>
JDK + Tomcat配置JSP开发环境
查看>>