题目描述
贝西工作勤勤恳恳,她每月向约翰索要C 元钱作为工资。约翰手上有不少钱,他一共有N 种面额的钞票。第i 种钞票的面额记作Vi,约翰有Ki 张。钞票的面额设定是比较合理的,保证所有大面额的钞票都是所有小面额钞票的整数倍。假设约翰每个月给贝西发一次工资,那么这些钱够发几个月的工资呢?贝西不会找零,如果约翰发的钱大于C 元,多余的部分就算是贝西的奖励了。
输入输出格式
输入格式:
第一行:两个整数N 和C,1 ≤ N ≤ 20, 1 ≤ C ≤ 109
第二行到第N + 1 行:第i + 1 行有两个整数Vi 和Ki,1 ≤ Vi ≤ 109; 1 ≤ Ki ≤ 106
输出格式:
单个整数:表示约翰最多能给贝西发几个月的工资
输入输出样例
输入样例#1:
3 6
10 1
1 100
5 120
输出样例#1:
111
说明
第一个月先给一张十元的,接下来十个月每个月都给两张五元的,最后一百个月每月给一张一元的和一张五元的。
正解思路:根据贪心策略,先把面值大于C的钞票花出去,不会使答案更差。对于面值小于C的钞票,先用较大面值的钞票凑,找到恰好能得到花费为c的情况(这样显然会让花费尽量少,显然更优)。若最后凑不出恰好为C的情况,尽量选择小面值的钞票去凑,一直到结束为止。
这题被拿来当考试题了,wa的一塌糊涂。错解思路:dfs+剪枝。也是先排一下序(从大到小),然后去搜恰好等于c的情况。然后剩下的再去大的和小的凑,如果能凑出来就凑,否则就加起来继续找继续凑,直到最后>c,ans++,一个类似于左右指针往中间移的思想。由于洛谷数据太水的缘故,这个可以在洛谷AC5个点,T4个点。一并贴上代码。
错解:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=25;
struct dqs
{
ll mz,num;//mz==面值
}hh[maxn],ha[maxn];
ll used[maxn];
bool cmp(dqs a,dqs b)
{
return a.mz>b.mz;
}
ll ans=0,n,c,tot;
void dfs(ll x,ll shu,ll pre,ll minnum)
{
if(shu>c) return;
if(used[pre]>ha[pre].num) return;
if(shu==c)
{
ans+=minnum;
for(ll i=1;i<=tot;i++)
ha[i].num-=minnum*used[i];
}
for(ll i=1;i<=tot;i++)
{
used[i]++;
dfs(i,shu+ha[i].mz,x,min(minnum,ha[i].num/used[i]));
used[i]--;
}
}
int main()
{
ll shu=0;
bool flag=0;
scanf("%lld%lld",&n,&c);
for(ll i=1;i<=n;i++)
{
scanf("%lld%lld",&hh[i].mz,&hh[i].num);
if(flag==0)
shu+=hh[i].mz*hh[i].num;
if(shu>=c) flag=1;
}
if(!flag)
{
puts("0");
return 0;
}
sort(hh+1,hh+n+1,cmp);
for(ll i=1;i<=n;i++)
{
if(hh[i].mz>=c) ans+=hh[i].num;
else ha[++tot]=(dqs){hh[i].mz,hh[i].num};
}
dfs(1,0,0,1e9);
for(ll i=1;i<=tot;i++)
{
ll cj=ha[i].num*ha[i].mz;
if(cj>c)
{
ll sss=ha[i].mz,sc;
while(sss<c)
sss+=ha[i].mz;
sc=cj/sss;
ans+=sc;
ha[i].num-=sc;
}
}
ll preshu=0,prei=0,lasti=0,lastshu=0;
for(ll i=1;i<=tot;i++)
{
if(ha[i].num!=0)
{
preshu=ha[i].mz;
prei=i;
break;
}
}
for(ll i=tot;i>=1;i--)
{
if(ha[i].num!=0)
{
lastshu=ha[i].mz;
lasti=i;
break;
}
}
while(prei!=lasti)
{
if(preshu+lastshu*ha[lasti].num>=c)
{
ans++;
lasti--;
if(ha[prei].num--==0)
prei++;
}
else
{
preshu+=lastshu*ha[lasti].num;
lasti--;
}
}
printf("%lld\n",ans);
return 0;
}
正解:
/*洛谷P2619*/
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int maxn=200005;
struct dqs
{
int mz,num;
}hh[maxn];
bool cmp(dqs a,dqs b)
{
return a.mz>b.mz;
}
int main()
{
int n,c,ans=0,tot=0;
scanf("%d%d",&n,&c);
for(int i=1;i<=n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
if(a>=c) ans+=b;
else hh[++tot]=(dqs){a,b};
}
sort(hh+1,hh+tot+1,cmp);
while(true)
{
int tmp=c;
for(int i=1;i<=tot;i++)
{
while(tmp>=hh[i].mz&&hh[i].num)
{
int shu=min(tmp/hh[i].mz,hh[i].num);
tmp-=shu*hh[i].mz;
hh[i].num-=shu;
}
}
if(tmp>0)
{
for(int i=tot;i>=1;i--)
if(tmp<=hh[i].mz&&hh[i].num)
{
hh[i].num--;
tmp=0;
break;
}
}
if(tmp>0) break;
ans++;
}
printf("%d\n",ans);
return 0;
}
/*
4 14
5 1
6 1
7 1
11 1*/