=== ===
这里放传送门
=== ===
题解
这其实是一道有点麻烦的乱搞题。。但是记得第一次写这题的时候蛋疼写了个二分啥的?但是反正没写出来= =考虑如果建造酿酒厂的点选定了,那么对于每个点只要考虑顺时针走过去比较好还是逆时针走过去比较好就可以了。并且这样的话就一定存在一个分界点,它左边的点都是顺时针走,右边的点都是逆时针走。而每个点对于每一条路径累加的花费都是固定的,就是它的需求乘以这条路径的长度。如果分界点逆时针移动了一个位置,就相当于在逆时针的花费中减少了一条边,顺时针的花费中增加了一条边。于是我们先预处理酒厂建在1号点的答案,然后把酒厂按顺序后移,显然那个分界点也是随着酒厂按照同样的顺序移动的,每次维护一下分界点的位置就可以了。可以用前缀和搞一搞。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,d[20010],e[20010],sd[20010],se[20010],now,cut;
long long ans,sum,mid;
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++){
scanf("%d%d",&e[i],&d[i]);
sd[i]=sd[i-1]+d[i];
se[i]=se[i-1]+e[i];
d[i+n]=d[i];e[i+n]=e[i];
}
for (int i=n+1;i<=2*n;i++){
sd[i]=sd[i-1]+d[i];
se[i]=se[i-1]+e[i];
}
mid=sd[n]/2;cut=1;now=1;
while (sd[cut-1]<mid){
ans+=(long long)e[cut]*(sd[cut-1]);
++cut;
}
for (int i=cut;i<=n;i++)
ans+=(long long)e[i]*(sd[n]-sd[i-1]);//计算在1号位置建造酒厂的花费
sum=ans;
for (int i=2;i<=n;i++){
sum-=(long long)d[i-1]*(se[cut-1]-se[i-1]);//减去去掉的那条边
while (sd[cut-1]-sd[i-1]<mid){//维护分界点
sum-=(long long)e[cut]*(sd[i+n-2]-sd[cut-1]);
sum+=(long long)e[cut]*(sd[cut-1]-sd[i-1]);
++cut;
}
sum+=(long long)d[i-1]*(se[i+n-1]-se[cut-1]);
if (sum<ans){
ans=sum;now=i;
}
}
printf("%lld\n",ans);
return 0;
}