[bzoj1042][HAOI2008]硬币购物
有三种硬币,每种有自己的币值。
然后有n次询问,每次都给出每种硬币的数量和要付的钱s,求有多少种付法。n<=1000 s<=100000
------
不考虑限制,就是个简单dp....
有限制的时候,我们可以考虑反过来用总的方案数量剪掉不合法的。
根据容斥原理,不合法的情况=
有1种硬币数量不合法即第1种不合法+第2+第3+第4 再去掉有两个不合法的12种都不合法-23种都不合法-34种都不合法-........加上三种不合法的即123种不合法+124不合法... 最后减去1234都不合法。
所以每次询问都这样做一遍,让一种硬币不合法只要付比他的限制多一个就可以了,剩下的钱可以随意付,直接去dp里查值。
复杂度4*s+n*2^4
#include<iostream> #include<cstdio> #define ll long long using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} return x*f; } ll ans; int c[5],x[5],n,s; ll f[100005]; void dfs(int i,int p,int sum) { // printf("%d %d %d\n",i,p,sum); if(i>4){ans+=p*f[sum];return;} dfs(i+1,p,sum); if(sum>=c[i]*(x[i]+1))dfs(i+1,-p,sum-c[i]*(x[i]+1)); } int main() { for(int i=1;i<=4;i++)c[i]=read(); f[0]=1; for(int i=1;i<=4;i++) for(int j=c[i];j<=100000;j++) f[j]+=f[j-c[i]]; n=read(); for(int i=1;i<=n;i++) { for(int j=1;j<=4;j++)x[j]=read();s=read();ans=0; dfs(1,1,s); printf("%lld\n",ans); } return 0; }
FallDream代表秋之国向您问好!
欢迎您来我的博客www.cnblogs.com/FallDream
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 理解Rust引用及其生命周期标识(下)
· 从二进制到误差:逐行拆解C语言浮点运算中的4008175468544之谜
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 2025成都.NET开发者Connect圆满结束
· 后端思维之高并发处理方案
· 千万级大表的优化技巧
· 在 VS Code 中,一键安装 MCP Server!
· 10年+ .NET Coder 心语 ── 继承的思维:从思维模式到架构设计的深度解析