题目描述
Zxr960115 is owner of a large farm. He feeds mm cute cats and employs pp feeders. There's a straight road across the farm and nn hills along the road, numbered from 1 to nn from left to right. The distance between hill ii and (i−1)(i−1) is didi meters. The feeders live in hill 1.
One day, the cats went out to play. Cat ii went on a trip to hill hihi , finished its trip at time titi , and then waited at hill hihi for a feeder. The feeders must take all the cats. Each feeder goes straightly from hill 1 to nn without waiting at a hill and takes all the waiting cats at each hill away. Feeders walk at a speed of 1 meter per unit time and are strong enough to take as many cats as they want.
For example, suppose we have two hills (d2=1)(d2=1) and one cat that finished its trip at time 3 at hill 2 (h1=2)(h1=2) . Then if the feeder leaves hill 1 at time 2 or at time 3, he can take this cat, but if he leaves hill 1 at time 1 he can't take it. If the feeder leaves hill 1 at time 2, the cat waits him for 0 time units, if the feeder leaves hill 1 at time 3, the cat waits him for 1 time units.
Your task is to schedule the time leaving from hill 1 for each feeder so that the sum of the waiting time of all cats is minimized.
输入格式
The first line of the input contains three integers n,m,pn,m,p (2≤n≤105,1≤m≤105,1≤p≤100)(2≤n≤105,1≤m≤105,1≤p≤100).
The second line contains n−1n−1 positive integers d2,d3,...,dnd2,d3,...,dn (1≤di<104).(1≤di<104).
Each of the next mm lines contains two integers hihi and titi (1≤hi≤n,0≤ti≤109)(1≤hi≤n,0≤ti≤109).
输出格式
Output an integer, the minimum sum of waiting time of all cats.
Please, do not write the %lld specifier to read or write 64-bit integers in С++. It is preferred to use the cin, cout streams or the %I64d specifier.
题意翻译
Zxr960115 是一个大农场主。
他养了 mm 只可爱的猫子,雇佣了 pp 个铲屎官。这里有一条又直又长的道路穿过了农场,有 nn 个山丘坐落在道路周围,编号自左往右从 11 到 nn。山丘 ii 与山丘 i−1i−1 的距离是 DiDi 米。铲屎官们住在 11 号山丘。
一天,猫子们外出玩耍。猫子 ii 去山丘 HiHi 游玩,在 TiTi 时间结束他的游玩,然后在山丘 HiHi 傻等铲屎官。铲屎官们必须把所有的猫子带上。每个铲屎官直接从 H1H1 走到 HnHn,中间不停下,可以认为不花费时间的把游玩结束的猫子带上。每个铲屎官的速度为一米每单位时间,并且足够强壮来带上任意数量的猫子。
举个栗子,假装我们有两个山丘( D2=1D2=1 ),有一只猫子,他想去山丘 22 玩到时间 33。然后铲屎官如果在时间 22 或者时间 33 从 11 号山丘出发,他就能抱走猫子。如果他在时间 11 出发那么就不行(猫子还在玩耍)。如果铲屎官在时间 22 出发,猫子就不用等他(ΔT=0ΔT=0)。如果他在时间 33 出发,猫子就要等他 11 个单位时间。
你的任务是安排每个铲屎官出发的时间(可以从 0 时刻之前出发),最小化猫子们等待的时间之和。
对于全部的数据,满足 2≤n≤1052≤n≤105,1≤m≤1051≤m≤105,1≤p≤1001≤p≤100,1≤Di<1041≤Di<104,1≤Hi≤n1≤Hi≤n,0≤t≤1090≤t≤109。
输入输出样例
输入 #1
4 6 2
1 3 5
1 0
2 1
4 9
1 10
2 10
3 12
输出 #1
3
CF311B Cats Transport
题目给的是每一只猫猫结束游玩的时间还有位置,但是其实这两个东西都是用来计算什么时候可以去接这只猫猫的
我们用一个数组a[i]表示什么时候时候让一个铲屎官出发可以刚刚好接到第i只猫猫
然后把a[i]从小到大排序,这样就直接把位置和结束时间这两个东西简化了
显然,我们 每一次派铲屎官出去都能够接到\(a[i]\)上连续的一段猫猫
不然dp都做不了。。因为如果不简化离散化都做不到,而\(t[i]<1e9\),这谁扛得住啊
这样就方便了,设\(f[i][j]\)表示已经用了j铲屎官接到了接前i只猫猫时的最小等待时间
方程很好写
\[f[i][j]= \displaystyle\max_{j-1\leq k \leq i-1}(f[k][j-1]+t[i]*(i-k)-sum(a[k],a[i])) \]然后拆开来,把能拿出max的拿出来
\[f[i][j]=\displaystyle\max_{j-1\leq k \leq i-1}(f[k][j-1]+t[i]*i-t[i]*k-suma[i]+suma[k]) \]发现里面有一个\(t[i]*k\) 的玩意,而且\(t[i]\)之间没有明显的规律,无法直接统计里面i变化时变化的东西来快速找到最优决策
但是这个i*k的形式是可以尝试斜率优化的
把max去掉,对式子进行一定的变形
基本出来了,可以滚动数组,但是没必要,t[i]没有单调性,要二分查找来找决策点,队头不需要出队,每次增加新元素的时候队尾出队就行
j放在外侧循环,是不变的,所以决策点不用因为这个出队
那如果j单调向右移动会不会导致不能做了?
好像不会啊,也是平衡树,然后决策前判断一下是否合法,不合法就删掉再找,反正平衡树删除也是\(log_2(n)\),每次都只进去一次,总体\(O(nlog(n))\)
已经...无所谓了
这题主要是前面的转化,我看到的时候其实就有点感觉,小猫的位置和结束时间只是共同决定了一个东西,既然这样,那为什么不直接把这个东西算出来呢?
很...朴实无华的想法,如果要难一些的话,可以把这个思路藏起来,不需要给这么明显的引导
那就真的难了
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read() {
char c=getchar();ll a=0,b=1;
for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
for(;c>='0'&&c<='9';c=getchar())a=a*10+c-48;return a*b;
}
ll n,m,p,pos[200001],Suma[200001];
ll f[200001][101];
ll q[200001],l,r;
struct cat
{
ll t,h,Suma,a;
}a[200001];
bool mycmp(cat a,cat b)
{
return a.a<b.a;
}
inline ll ry(ll x,ll j)
{
return f[x][j-1]+a[x].Suma;
}
inline ll Y(ll a,ll b,ll c,ll j) //斜率
{
ll x1=a-b, x2=b-c, y1=ry(a,j)-ry(b,j), y2=ry(b,j)-ry(c,j);
return x1*y2-x2*y1;
}
inline ll calc(ll i,ll j,ll k)//y-kx
{
return ry(k,j)-a[i].a*k;
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
n=read(),m=read(),p=read();
// cout<<m<<endl;
for(ll i=2;i<=n;i++)pos[i]=pos[i-1]+read();
for(ll i=1;i<=m;i++)
{
a[i].h=read(),a[i].t=read();
a[i].a=a[i].t-pos[a[i].h];
}
sort(a+1,a+1+m,mycmp);
for(ll i=1;i<=m;i++)a[i].Suma=a[i-1].Suma+a[i].a;
for(ll i=1;i<=m;i++)
{
f[i][1]=a[i].a*i-a[i].Suma;
}
ll ans=f[m][1];
for(ll j=2;j<=p;j++)
{
l=r=1;
q[r]=0;
for(ll i=1;i<=m;i++)
{
// while(l<r&&((f[q[l]][j-1]+a[q[l]].Suma)-(f[q[l+1]][j-1]+a[q[l+1]].Suma))<=a[i].a*(q[l]-q[l+1]))l++;
while(l<r&&f[q[l+1]][j-1]+a[q[l+1]].Suma-a[i].a*q[l+1]<f[q[l]][j-1]+a[q[l]].Suma-a[i].a*q[l])l++;
// cout<<l<<' ';
// cout<<j<<' '<<q[l]<<endl;
f[i][j]=f[q[l]][j-1] +a[q[l]].Suma -a[i].Suma +a[i].a*(i-q[l]);
while(l<r&&(ry(q[r],j)-ry(i,j))*(q[r-1]-i)<=(ry(q[r-1],j)-ry(i,j))*(q[r]-i))r--;
q[++r]=i;
}
ans=min(ans,f[m][j]);
}
cout<<ans<<endl;
return 0;
}
这题。。
我推的式子,5步错了三次
全是符号错了,最后写的时候还把大于小于打反了
我真的是服了
焯!