题目
题解
很自然的想法,首先一定会按照
排序。
设
表示前i个物品,第i个物品一定购买的时候最大的魂力。
转移的时候,就枚举上一个购买的物品j,
计算这一段时间j物品的收益。
这样子是
的。
整理一下式子,就变成了:
可以看出,对于每一个不同的i,相同的j的影响是一个一次函数,
也就是一条直线,斜率为
由于
并没有单调性,所以就不能用单调队列或者栈来维护。
用线段树来维护。
线段树的一个区间,表示一条线段,
如果新插入的线段完全大于原有的线段,
就整个区间直接用新的线段去替换。
如果新旧线段有交点,
那么就分别递归到下面一层。
查询的时候,就将包含这个点的每个区间的线段取个max就可以了。
code
#include <queue>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#include <time.h>
#define ll long long
#define N 100003
#define M 103
#define db double
#define P putchar
#define G getchar
#define inf 998244353
#define pi 3.1415926535897932384626433832795
using namespace std;
char ch;
void read(ll &n)
{
n=0;
ch=G();
while((ch<'0' || ch>'9') && ch!='-')ch=G();
ll w=1;
if(ch=='-')w=-1,ch=G();
while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
n*=w;
}
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
ll abs(ll x){return x<0?-x:x;}
ll sqr(ll x){return x*x;}
void write(ll x){if(x>9) write(x/10);P(x%10+'0');}
struct node
{
ll d,p,r,g;
}a[N];
struct arr
{
ll k,b;
int l,r;
}tr[N*50],w;
bool cmp(node a,node b)
{
return a.d<b.d;
}
ll n,f[N],q,m,c,d,tot,t;
void work()
{
for(int i=1;i<=n;i++)
{
for(int j=i-1;j>=0;j--)
{
t=f[j]+(a[i].d-a[j].d-1)*a[j].g+a[j].r;
if(t>=a[i].p)f[i]=max(f[i],t-a[i].p);
}
}
}
void ins(int x,ll l,ll r)
{
ll t1=w.k*l+w.b,t2=w.k*r+w.b;
ll w1=tr[x].k*l+tr[x].b,w2=tr[x].k*r+tr[x].b;
if((t1>=w1 && t2>=w2))
{
tr[x].k=w.k;
tr[x].b=w.b;
return;
}
if(l==r || (t1<w1 && t2<w2))return;
ll m=(l+r)>>1;
if(!tr[x].l)tr[x].l=++tot,tr[tot].b=tr[tot].k=tr[tot].l=tr[tot].r=0;
if(!tr[x].r)tr[x].r=++tot,tr[tot].b=tr[tot].k=tr[tot].l=tr[tot].r=0;
ins(tr[x].l,l,m);
ins(tr[x].r,m+1,r);
}
ll find(int x,ll l,ll r,ll pos)
{
if(x==0)return 0;
if(l==r)return pos*tr[x].k+tr[x].b;
ll m=(l+r)>>1;
if(pos<=m)return max(pos*tr[x].k+tr[x].b,find(tr[x].l,l,m,pos));
else return max(pos*tr[x].k+tr[x].b,find(tr[x].r,m+1,r,pos));
}
int main()
{
freopen("practice.in","r",stdin);
freopen("practice.out","w",stdout);
for(read(m),read(q);q;q--)
{
memset(f,128,sizeof(f));
read(n);read(c);read(d);
for(int i=1;i<=n;i++)
read(a[i].d),read(a[i].p),read(a[i].r),read(a[i].g);
d++;n++;a[n].d=d;a[n].p=a[n].g=a[n].r=0;
sort(a+1,a+1+n,cmp);
tot=1;tr[tot].b=c;tr[tot].k=tr[tot].l=tr[tot].r=0;
for(int i=1;i<=n;i++)
{
t=find(1,1,d,a[i].d);
if(t<a[i].p)continue;
f[i]=t-a[i].p;
w.k=a[i].g;w.b=f[i]+a[i].r-(a[i].d+1)*a[i].g;
ins(1,1,d);
}
write(f[n]);P('\n');
}
return 0;
}