这是题目的整体代码:
#include<cmath>
#include<map>
#define int long long
using namespace std;
const int N=3e5+9;
int f[N];//前i个分成若干个的小收益
int s[N];//时间前缀和
int e[N];//费用系数前缀和
int q[N];
int t;//开机花费时间
int n;
int head=1,tail=0;
int read()
{
int f=1,x=0;
char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=(x<<1)+(x<<3)+(s^'0');s=getchar();}
return f*x;
}
long double Y(int j)
{
return (long double)f[j]-(long double)e[j]*(long double)t;
}
long double X(int j)
{
return (long double)e[j];
}
long double slope(int i,int j)
{
return X(j)==X(i)?(Y(j)>=Y(i)?1e18:-1e18):(long double)(Y(j)-Y(i))/(X(j)-X(i));
}
void DP()
{
for(int i=1;i<=n;i++)
{
int l=head;
int r=tail;
int pos=0;
while(l<r)
{
int mid=(l+r)>>1;
if(slope(q[mid],q[mid+1])<=s[i])
{
pos=mid+1;
l=mid+1;
}
else r=mid;
}
f[i]=f[q[pos]]+s[i]*e[i]-s[i]*e[q[pos]]+t*e[n]-t*e[q[pos]];
while(head<tail and slope(q[tail-1],q[tail])>slope(q[tail],i))
tail--;
q[++tail]=i;
}
}
signed main()
{
n=read();
t=read();
for(int i=1;i<=n;i++)
{
s[i]=s[i-1]+read();
e[i]=e[i-1]+read();
}
q[++tail]=0;
DP();
printf("%lld\n",f[n]);
}
写了两种不同的二分方法:
一、90pts。
int l=head;
int r=tail;
int pos=0;
while(l<=r)
{
int mid=(l+r)>>1;
if(slope(q[mid-1],q[mid])<=s[i])
{
pos=mid;
l=mid+1;
}
else r=mid-1;
}
f[i]=f[q[pos]]+s[i]*e[i]-s[i]*e[q[pos]]+t*e[n]-t*e[q[pos]];
二、100pts
int l=head;
int r=tail;
if(l==r) goto Here;
while(l<r)
{
int mid=(l+r)>>1;
if(slope(q[mid],q[mid+1])<=s[i])
l=mid+1;
else r=mid;
}
Here:;
f[i]=f[q[l]]+s[i]*e[i]-s[i]*e[q[l]]+t*e[n]-t*e[q[l]];
自我感觉这两种二分方法是一样的哇/kk,但是第一种为什么会出错呢T^T。