题目描述
训练师小梁在一次机缘巧合中,发现了一个皮卡丘部落,她非常喜欢皮卡丘,但由于精灵球有限,所以她打算在这里逗留一段时间,部落中有\text{n}n个皮卡丘,每个皮卡丘有不同的可爱度qi ,小梁要欣赏这些皮卡丘,但有的皮卡丘被看多了会抑郁,所以她要合理的分配时间和看的次数,收获最多的可爱度。
输入描述:
到达部落的时间e, s(24小时制时间),皮卡丘的个数n(s≤e,n≤10 5 )下面n行t,q,s分别代表:欣赏这只皮卡丘需要的时间(分钟),这只皮卡丘的可爱度,这只皮卡丘最多能看几次(s=0表示这只皮卡丘脾气很好,能看无限次)
输出描述:
一个整数,表示能获取的最大可爱度
示例1
输入
5:30 7:10 5
3 1 5
4 4 2
2 1 0
4 5 3
5 6 0
输出
120
题目中把n个皮卡丘理解为n种物品,需要的时间理解为体积,获得的可爱度理解为价值,在加上有限定次数,可以显而易见的看出这道题是一道多重背包,再看题面中的数据范围n为10000,n^3的多重背包写法必定会超时,这就要用到了二进制优化。
二进制优化基于数论的一个知识,任意的一个整数中的任意的一个数,都可以由所有不大于这个整数的的
2^n的数组合而成,例如18=1+2+4+8+3, 18中的任意数都可以由1,2,4,8,3组合而成。
当p[i]=0时说明可以无限拿,可以直接转换成完全背包。
其中关于开始时间和结束时间转换成时间段大小有多种方法(这里列出两种,模拟或scanf的格式读入)
我们定义状态dp[s]表示当时间段大小为s时,能获得的最大可爱度。
状态转移方程为
dp[j]=max(dp[j],dp[j−t[i]]+c[i])
dp[k]=max(dp[k],dp[k−j∗t[i]]+j∗c[i])
我写的2进制优化程序只能过80%,原因不知道。
#include<bits/stdc++.h>
#include<bitset>
#include<unordered_map>
#define pb push_back
#define bp __builtin_popcount
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=1e6+100;
const int MOD=1e9+7;
int lowbit(int x){return x&-x;}
inline ll dpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % MOD; b >>= 1; t = (t*t) % MOD; }return r; }
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t); b >>= 1; t = (t*t); }return r; }
int n,m,x1,x2,y11,y22,t,q,s;
ll dp[maxn];
struct node{
int x,y;
};
vector<node>G;
int main()
{
scanf("%d:%d%d:%d%d",&x1,&y11,&x2,&y22,&n);
m=(x2-x1)*60+y22-y11;
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&t,&q,&s);//一次消耗的时间 一次获得的可爱度 次数
if(s==0||s>m/t)s=m/t;
for(int c=1;c<=s;c<<1)
{
G.push_back(node{t*c,q*c});
s-=c;
}
if(s)G.push_back(node{t*s,q*s});
}
for(auto it:G)
for(int j=m;j>=it.x;j--)
{
dp[j]=max(dp[j],dp[j-it.x]+it.y);
}
cout<<dp[m]<<endl;
system("pause");
return 0;
}
可能是因为vector储存方式比较慢导致的。
AC代码如下
#include<cstdio>
int n,m,s,f[10000],a[1100005],b[1100005],x1,y1,x2,y2,w,v,k,x;
inline int max(int a,int b){return a>b?a:b;}
int main()
{
scanf("%d:%d%d:%d%d",&x1,&y1,&x2,&y2,&n);
s=(x2-x1)*60+y2-y1;
for(int i=0;i<n;++i)
{
scanf("%d%d%d",&w,&v,&k);
if(k==0||k>s/w)k=s/w;
for(x=1;x<=k;x<<=1)a[++m]=x*w,b[m]=x*v,k-=x;
if(k)a[++m]=k*w,b[m]=k*v;
}
for(int i=1;i<=m;++i)
{
for(int j=s;j>=a[i];--j)
f[j]=max(f[j-a[i]]+b[i],f[j]);
}
printf("%d",f[s]);
}