题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1042

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<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
ll c[],d[][],tot,mx,s[],f[],ans;
void pre()
{
f[]=;///
for(int i=;i<=;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<)return;//不是z<=0!!
if(k==)
{
if(cnt&)ans-=f[z];
else if(cnt)ans+=f[z];
return;
}
dfs(now,k+,cnt,z);
dfs(now,k+,cnt+,z-c[k]*d[now][k]-c[k]);
}
int main()
{
for(int i=;i<=;i++)scanf("%lld",&c[i]);
scanf("%lld",&tot);
for(int i=;i<=tot;i++)
scanf("%lld%lld%lld%lld%lld",&d[i][],&d[i][],&d[i][],&d[i][],&s[i]),mx=max(mx,s[i]);
pre();
for(int i=;i<=tot;i++)
{
ans=f[s[i]];
dfs(i,,,s[i]);
printf("%lld\n",ans);
}
return ;
}

高精WA代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int INF=;
ll c[],d[][],tot,s[],mx,tp;
int f[INF][],ans[];
void plu(ll k,int a[],int b[])
{
int tmp[]={},lm=max(a[],b[]);
for(int i=;i<=lm;i++)
{
tmp[i]+=a[i]+b[i];
if(tmp[i]>)tmp[i]-=,tmp[i+]++;
}
tmp[]=lm;
if(tmp[tmp[]+])tmp[]++;
memcpy(f[k],tmp,sizeof tmp);
}
void pre()
{
f[][]=;f[][]=;
for(int i=;i<=;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[];i;i--)
printf("%d",ans[i]);
printf("\n");
}
void plu2(ll k)
{
int lm=max(ans[],f[k][]);
for(int i=;i<=lm;i++)
{
ans[i]+=f[k][i];
if(ans[i]>)ans[i]-=,ans[i+]++;
}
if(ans[ans[]+])ans[]++;
// printf("++ k=%d ",k);print();
}
void jian(ll k)
{
// int lm=max(ans[0],f[k][0]);
for(int i=;i<=f[k][];i++)
{
ans[i]-=f[k][i];
if(ans[i]<)ans[i]+=,ans[i+]--;
}
while(!ans[ans[]]&&ans[]>)ans[]--;
// 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=;i<=;i++)scanf("%lld",&c[i]);
scanf("%lld",&tot);
for(int i=;i<=tot;i++)
{
scanf("%lld%lld%lld%lld%lld",&d[i][],&d[i][],&d[i][],&d[i][],&s[i]);
mx=max(mx,s[i]);
}
pre();
for(int i=;i<=tot;i++)
{
memcpy(ans,f[s[i]],sizeof f[s[i]]);//
// debugprint();
for(int u=;u<;u++)
for(int v=u+;v<=;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[]*d[i][]+c[]*d[i][]+c[]*d[i][]+c[]*d[i][]+c[]+c[]+c[]+c[];
if(tp<=s[i])plu2(s[i]-tp);
for(int u=;u<=;u++)
{
tp=c[u]*d[i][u]+c[u];
if(tp<=s[i])jian(s[i]-tp);
}
for(int u=;u<=;u++)
for(int v=u+;v<=;v++)
for(int j=v+;j<=;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 ;
}

bzoj1042硬币购物的更多相关文章

  1. bzoj1042硬币购物——递推+容斥

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1042 递推,再用容斥原理减掉多余的,加上多减的……(dfs)即可. 代码如下: #includ ...

  2. [bzoj1042]硬币购物

    先预处理出没有上限的方案数,然后容斥,然后将所有东西的范围都变为[0,+oo),即可用预处理出的dp数组计算 1 #include<bits/stdc++.h> 2 using names ...

  3. BZOJ1042 [HAOI2008]硬币购物 完全背包 容斥原理

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1042 题目概括 硬币购物一共有4种硬币.面值分别为c1,c2,c3,c4.某人去商店买东西,去了t ...

  4. 【BZOJ1042】硬币购物(动态规划,容斥原理)

    [BZOJ1042]硬币购物(动态规划,容斥原理) 题面 BZOJ Description 硬币购物一共有4种硬币.面值分别为c1,c2,c3,c4.某人去商店买东西,去了tot次.每次带di枚ci硬 ...

  5. [bzoj1042][HAOI2008][硬币购物] (容斥原理+递推)

    Description 硬币购物一共有4种硬币.面值分别为c1,c2,c3,c4.某人去商店买东西,去了tot次.每次带di枚ci硬币,买si的价值的东西.请问每次有多少种付款方法. Input 第一 ...

  6. 【BZOJ-1042】硬币购物 容斥原理 + 完全背包

    1042: [HAOI2008]硬币购物 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1811  Solved: 1057[Submit][Stat ...

  7. bzoj1042: [HAOI2008]硬币购物

    #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #i ...

  8. 【BZOJ1042】【DP + 容斥】[HAOI2008]硬币购物

    Description 硬币购物一共有4种硬币.面值分别为c1,c2,c3,c4.某人去商店买东西,去了tot次.每次带di枚ci硬币,买si的价值的东西.请问每次有多少种付款方法. Input 第一 ...

  9. BZOJ1042:[HAOI2008]硬币购物(DP,容斥)

    Description 硬币购物一共有4种硬币.面值分别为c1,c2,c3,c4.某人去商店买东西,去了tot次.每次带di枚ci硬币,买si的价值的东西.请问每次有多少种付款方法. Input 第一 ...

随机推荐

  1. shell里的/dev/null 2>&1详解

    shell中可能经常能看到: >/dev/null 2>&1 命令意思是:标准输出stdout 和标准错误输出stderr 也重定向到空设备文件,即不显示输出信息 分解这个组合:“ ...

  2. 4.16复杂级数的前n项和

    注意:实际编程中要注意变量类型的选取. #include <iostream> #include<cstdio> using namespace std; int main() ...

  3. java 继承 初始化顺序

    面向对象三大特性: 封装,继承,多态 java 继承初始化顺序 先初始化父类对象, 在父类对象中先初始化父类属性,再初始化父类的构造方法,然后初始化子类对象,初始化子类对象的属性,初始化子类的构造方法 ...

  4. SharePoint 用户配置文件服务

    1. 获取用户配置文件服务应用程序标识 Get-SPServiceApplication 2. 获取指定的用户配置文件服务应用程序实例 $profileSA = Get-SPServiceApplic ...

  5. windows : Jmeter自动化测试-eclipse+maven+jmeter

    前提 在window上已经安装maven并且在eclipse中配置好了maven,如果没有配置,参考文章   windows上安装maven及eclipse中配置maven 一.创建一个包含jmete ...

  6. spring事务管理及相关知识

    最近在项目中遇到了spring事务的注解及相关知识,突然间感觉自己对于这部分知识只停留在表面的理解层次上,于是乎花些时间上网搜索了一些文章,以及对于源码的解读,整理如下: 一.既然谈到事务,那就先搞清 ...

  7. jquery 中事件

    jQuery 事件 - submit() 方法 定义和用法 当提交表单时,会发生 submit 事件. 该事件只适用于表单元素. submit() 方法触发 submit 事件,或规定当发生 subm ...

  8. Android 获取联系人和电话号码

    获取联系人和电话号码 private void queryContactPhoneNumber() { String[] cols = {ContactsContract.PhoneLookup.DI ...

  9. 【linux基础】查看硬盘位置信息

    nvidia@tegra-ubuntu:/media/nvidia/Elements/data$

  10. PDB调试模块

    这里主要是一些对于调试常用的命令:1.直接通过命令端输入进行调试 以pdb调试模式运行(主要用这个) python3 -m pdb file.py 2.在代码中导入pdb模块 import pdb 功 ...