[CF311B] Cats Transport
思路
我们发现每只小猫有两个对接走时间有影响的参数
求出
这样,我们就把问题转化成了每个铲屎官要带走哪一段连续区间的小猫的问题,也就是区间划分问题,可以正常地
设
求和部分可以用前缀和解决。然鹅还是要枚举
观察发现该式子有且仅有一个
先把求和化成前缀和相减的形式。 设
考虑在
消掉等式两边相同的项,化简后可得:
设
这样用一个单调队列维护即可。
代码
#include<bits/stdc++.h>
#define MAXN 100010
#define int long long
#define INF 0x7fffffffffff
using namespace std;
int n,m,q,d[MAXN],a[MAXN],sum[MAXN],x,y,dp[110][MAXN];//前i个铲屎官带走前j只猫
int arr[MAXN],up=0,down=0;
long double f(int x,int i)
{
return dp[i-1][x]+sum[x]+0.0;
}
long double k(int a,int b,int i)
{
if(a==b)return -INF;
return (f(a,i)-f(b,i))/(a-b+0.0);
}
signed main()
{
scanf("%lld%lld%lld",&n,&m,&q);
for(int i=2;i<=n;i++)
scanf("%lld",&d[i]),d[i]+=d[i-1];
for(int i=1;i<=m;i++)
{
scanf("%lld%lld",&x,&y);
a[i]=y-d[x];
}
sort(a+1,a+m+1);
for(int i=1;i<=m;i++)
sum[i]=sum[i-1]+a[i];
for(int i=1;i<=m;i++)
dp[0][i]=INF;
for(int i=1;i<=q;i++)
{
up=down=0;
for(int j=0;j<=m;j++)
{
while(up<down&&k(arr[up],arr[up+1],i)<=a[j]+0.0)up++;
int kk=arr[up];
dp[i][j]=dp[i-1][kk]+a[j]*(j-kk)-sum[j]+sum[kk];
while(up<down&&k(arr[down-1],arr[down],i)>k(arr[down],j,i))down--;
arr[++down]=j;
}
}
printf("%lld",dp[q][m]);
return 0;
}
/*
dp[i][j]=min(dp[i-1][k]+a[j]*(j-k)-(sum[j]-sum[k]))
*/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!