题目大意:有n颗樱花树,你的总时间为T,现在n课树,每次观看要花费w时间,能获取v点价值,最多能参观s次,如果s等于0,则可以观看无限次,问你在T时间内 获得的最大价值是多少。
思路:这道题是一道混合背包的题,但是时间n《=10000,会超时,所以要用到二进制拆分优化。
把s[i]拆分为1+2+3+4+。。。+2……k,然后就可以转化为01背包的问题,完全背包可以把他的空间记为999999,不要太大,一般百万就足够了
代码:
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f3f3f3f3f
#define inf 0x3f3f3f3f
#define FILL(a,b) (memset(a,b,sizeof(a)))
#define re register
#define lson rt<<1
#define rson rt<<1|1
#define lowbit(a) ((a)&-(a))
#define ios std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
#define fi first
#define rep(i,n) for(int i=0;(i)<(n);i++)
#define rep1(i,n) for(int i=1;(i)<=(n);i++)
#define se second
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int > pii;
int dx[4]= {-1,1,0,0},dy[4]= {0,0,1,-1};
const ll mod=10007;
const ll N =1e6+10;
const double eps = 1e-4;
const double pi=acos(-1);
ll gcd(int a,int b){return !b?a:gcd(b,a%b);}
int f[N];
int n,cnt,t,p1[N],p2[N];
int lh,lm,rh,rm;
int w[N],v[N],s[N];
void dis()
{
for(int i=1;i<=n;i++)
{
int a=1;
while(s[i]!=0)
{
p1[++cnt]=w[i]*a;
p2[cnt]=v[i]*a;
s[i]-=a;
a*=2;
if(s[i]<a)
{
p1[++cnt]=w[i]*s[i];
p2[cnt]=v[i]*s[i];
break;
}
}
}
}
int main()
{
scanf("%d:%d%d:%d%d",&lh,&lm,&rh,&rm,&n);
int time=-lh*60-lm+rh*60+rm;
//out<<time<<endl;
for(int i=1;i<=n;i++)
{
cin>>w[i]>>v[i]>>s[i];
if(s[i]==0) s[i]=9999999;
}
dis();
for (int i = 1; i <= cnt; i ++ )
for (int j = time; j>=p1[i]; j--)
{
f[j]=max(f[j],f[j-p1[i]]+p2[i]);
}
cout<<f[time];
return 0;
}