题目描述
懒得改
奥妙重重的题面
10%
暴力?
O(2n)
30%
Dp,按照时间排序
设f[i]表示当前买第i个魂导器的最大收益。
则
f[i]=max(f[i],f[j]+r[j]+(d[i]−d[j]−1)∗g[j])−p[i]
O(n2)
40%
奇怪的水法优化
维护一个队列,满足头和尾不会出现一种方案完全优于前/后一种方案
O(n2−玄)
60%
因为D[i]>D[j]时,G[i]>G[j]
那么按照时间d来排序,那么每次从时间前的转移到时间后的一定最优
斜率优化乱搞
具体看https://blog.youkuaiyun.com/qq_36551189/article/details/79835607
O(nlogn)
70%
伪·斜率优化
不会
O(玄)
100%
60分的做法是按照时间d来排序,实际上可以按g来排序。
那么从前转移到后可以保证g单调最优。
因为
f[i]=max(f[i],f[j]+r[j]+(d[i]−d[j]−1)∗g[j])−p[i]
f[i]=max(f[i],
f[j]+r[j]-d[j]*g[j]-g[j]+
d[i]∗g[j])−p[i]
所以设标红部分为G[i]
f[i]=max(f[i],G[i]+d[i]∗g[j])−p[i]
设当前i有j、k两个状态可以转移过来(j< k)
如果k比j优
di∗gj+Gj<di∗gk+Gk
di∗(gj−gk)<Gk−Gj
di>Gk−Gjgj−gk
(因为是按g来排序)
因为di 不单调,所以每次用二分来找
可以看出维护的是一个下凸壳,每次只用删去尾部
那么当 xl(dt−1,dt)>xl(dt,i) 时便不满足下凸壳的性质,删去尾部
code
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define max(a,b) (a>b?a:b)
using namespace std;
long long d[100001];
long long p[100001];
long long r[100001];
long long g[100001];
long long f[100001];
long long G[100001];
long long _d[100001];
long long n,C,D,Q,i,j,k,l,ans,t,L,R,mid;
void swap(long long &a,long long &b) {long long c=a;a=b;b=c;}
void qsort(long long L,long long R)
{
long long i,j,mid;
i=L;
j=R;
mid=g[(L+R)/2];
while (i<=j)
{
while (g[i]<mid) i++;
while (g[j]>mid) j--;
if (i<=j)
{
swap(d[i],d[j]);
swap(p[i],p[j]);
swap(r[i],r[j]);
swap(g[i],g[j]);
i++,j--;
}
}
if (L<j) qsort(L,j);
if (i<R) qsort(i,R);
return;
}
double xl(int j,int k) {return double((G[k]-G[j])/(g[j]-g[k]));}
int main()
{
freopen("practice.in","r",stdin);
freopen("practice.out","w",stdout);
scanf("%lld%lld",&i,&Q);
for (;Q;Q--)
{
memset(f,128,sizeof(f));
scanf("%lld%lld%lld",&n,&f[0],&D);
fo(i,1,n)
scanf("%lld%lld%lld%lld",&d[i],&p[i],&r[i],&g[i]);
qsort(1,n);
t=1,_d[1]=0;
G[0]=f[0];
fo(i,1,n)
{
L=2;
R=t;
while (L<R)
{
mid=(L+R)/2;
if (xl(_d[mid-1],_d[mid])<d[i])
L=mid+1;
else
R=mid;
}
if (t>1)
{
if (xl(_d[L-1],_d[L])>=d[i]) L--;
}
else
L=1;
j=_d[L];
f[i]=d[i]*g[j]+G[j]-p[i];
if (f[i]>=0)
{
G[i]=f[i]+r[i]-d[i]*g[i]-g[i];
if (t && g[_d[t]]==g[i])
{
if (G[i]>G[_d[t]]) t--;
else continue;
}
while (t>1 && xl(_d[t-1],_d[t])>xl(_d[t],i))
t--;
_d[++t]=i;
}
}
ans=0;
fo(i,0,n)
if (f[i]>=0)
ans=max(ans,f[i]+r[i]+(D-d[i])*g[i]);
printf("%lld\n",ans);
}
fclose(stdin);
fclose(stdout);
return 0;
}
后记
作为一个万年写不对斜率优化的OIer居然一次过了2333