Description
Input
Output
Sample Input
1 3
3 2
4 3
2 3
1 4
Sample Output
這題完成的時間是有負數的,但是似乎費用係數Fi沒負數。
明明兩個輸入的描述是一樣的。。也不知道出題人在想什麼。。或者說畢竟SDOI麼
我們考慮從後往前轉移 F,T均爲後綴和
f[i]=min(f[j]+(Ti-Tj+S)*Fi)
大概這樣一個轉移式。
假設j<k,j比k優,
即f[j]+(Ti-Tj+S)*Fi<f[k]+(Ti-Tk+S)*Fi
移項後得
f[j]-f[k]<Fi*(Tj-Tk)
因爲T不是單調的所以沒辦法做除法。
我們考慮cdq分治
假設當前區間是[l,r]
則先把[mid,r]的答案處理出來,然後把[mid,r]中的T按照升序排序
這樣就保證了T的單調性,暴力維護出凸殼
然後對於[l,mid],因爲F是單調的,所以直接順着凸殼掃過去找到最優轉移位置就可以了
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
struct quest
{
long long t,f;
long long fx;
int p;
}a[300005],b[300005];
inline bool cmp(quest x,quest y)
{
return x.p<y.p;
}
int q[300005];
long long f[300005];
long long s;
inline bool check(int x,int y,int z)
{
return (a[z].t-a[y].t)*(a[y].fx-a[x].fx)>=(a[z].fx-a[y].fx)*(a[y].t-a[x].t);
}
inline bool getk(int x,int y,long long z)
{
return (a[y].fx-a[x].fx)<z*(a[y].t-a[x].t);
}
inline long long calc(int x,int i)
{
return a[x].fx+a[i].f*(a[i].t-a[x].t+s);
}
inline void solve(int ll,int rr)
{
if(ll==rr-1)
{
return ;
}
int mid=(ll+rr)/2;
solve(mid,rr);
int i;
int l=1,r=0;
for(i=rr-1;i>=mid;i--)
{
while(r>1&&check(q[r-1],q[r],i))
r--;
r++;
q[r]=i;
}
for(i=mid-1;i>=ll;i--)
{
while(l<r&&getk(q[l],q[l+1],a[i].f))
l++;
a[i].fx=min(a[i].fx,calc(q[l],i));
}
solve(ll,mid);
int d1=rr-1,d2=mid-1;
for(i=rr-1;i>=ll;i--)
{
if(d1<=mid-1)
{
b[i]=a[d2];
d2--;
}
else if(d2<=ll-1)
{
b[i]=a[d1];
d1--;
}
else
{
if(a[d2].t<a[d1].t||a[d2].t==a[d1].t)
{
b[i]=a[d2];
d2--;
}
else
{
b[i]=a[d1];
d1--;
}
}
}
for(i=ll;i<=rr-1;i++)
a[i]=b[i];
}
int main()
{
int n;
scanf("%d%lld",&n,&s);
int i;
for(i=1;i<=n;i++)
{
scanf("%lld%lld",&a[i].t,&a[i].f);
a[i].p=i;
}
for(i=n;i>=1;i--)
{
a[i].t=a[i+1].t+a[i].t;
a[i].f=a[i+1].f+a[i].f;
a[i].fx=a[i].f*(a[i].t+s);
}
solve(1,n+1);
sort(a+1,a+1+n,cmp);
printf("%lld\n",a[1].fx);
return 0;
}