# 洛谷 P3819 松江 1843 路
洛谷 P3819 松江 1843 路
提供一个比较无脑的解法。
思路
将所有点排完序后,可以发现整条数轴被分成 $ n+1 $ 个区间,由于两端必然不可能成为答案,所以只考虑中间 $ n-1 $ 段。
假设最优选择位置为 $ x_{0} $ ,我们可以得到距离和计算公式 $ S = \displaystyle \sum_{i=1}^{n} r_{i} \times | x_{0}-x_{i} | $ 。
考虑如何去掉绝对值,发现当 $ x_{0} \in [x_{i},x_{i+1}] $ ,$ S $ 可以唯一确定函数表达式,并且发现其为一次函数,所以最值在两端取到。
综上,只需要对每段区间维护出一次函数的系数和常数项,然后带入两个端点不断取最小值即可。函数解析式的系数与常数可以动态维护。
时间复杂度瓶颈在于排序:$ O(n \cdot logn) $ 。
code
code
#include <bits/stdc++.h>
#define i8 __int128
#define int long long
#define ull unsigned long long
#define fuck inline
#define lb long double
using namespace std;
// typedef long long ll;
const int N=3e5+5,mod=1e9+7,mod2=1e9+3342522;
const int INF=1e9+7;
const int inf=LONG_LONG_MAX/2;
// const int mod1=469762049,mod2=998244353,mod3=1004535809;
// const int G=3,Gi=332748118;
// const int M=mod1*mod2;
fuck int read()
{
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-'){f=-1;}c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c-'0');c=getchar();}
return x*f;
}
fuck void write(int x)
{
if(x<0){putchar('-');x=-x;}
if(x>9) write(x/10);
putchar(x%10+'0');
}
int L,n;
struct node
{
int x,r;
}a[N];
fuck bool cmp(node a,node b){return a.x<b.x;}
int ans1=0,ans2=0;
int ans=inf;
fuck void solve()
{
cin>>L>>n;
for(int i=1;i<=n;i++)cin>>a[i].x>>a[i].r,ans1+=(-a[i].r),ans2+=(a[i].r*a[i].x);
sort(a+1,a+n+1,cmp);
for(int i=1;i<n;i++)
{
ans1+=(2*a[i].r);
ans2-=(2*a[i].r*a[i].x);
ans=min(ans,min(ans1*a[i].x+ans2,ans1*a[i+1].x+ans2));
}
cout<<ans<<"\n";
}
signed main()
{
// ios::sync_with_stdio(false);
// cin.tie(0); cout.tie(0);
// int QwQ=read();
// int fuckccf=read();
// while(QwQ--)solve();
solve();
return 0;
}
// 6666 66666 666666
// 6 6 6 6 6
// 6 6 6666 6
// 6 6 6 6 6
// 6666 6 6 6666666
完结收工!!!!!

看完点赞,养成习惯
\(\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\)

浙公网安备 33010602011771号