题意:给出m个洞的位置和容量 和n个老鼠的位置
问所有老鼠都进洞的最小总和距离
解:
1、刚开始考虑费用流--->建边太多
2、看题解--->DP
(1)对老鼠和洞都进行排序
(2)dp[i][j]前i洞的情况下,前j个老鼠都进洞的最小总和
那么有
dp[i][j]=min{dp[i-1][k]+sum[i][j]-sum[i-1][k]}; k的范围为 [j-a[i].num,j-1]
所以dp[i][j]就从适合的k里转移过来 --->类似滑动窗口--->单调队列优化DP
#include<bits/stdc++.h>
#define en '\n'
#define ll long long
const ll inf=0x3f3f3f3f3f3f3f3f;
using namespace std;
const ll maxn =5009;//1e5+10;
ll read(){
ll qqq;scanf("%lld",&qqq);return qqq;
}
ll n,m;
ll pos[maxn];
ll dp[maxn][maxn],sum[maxn],S,q[maxn];
struct node{
ll pos,num;
bool operator <(const node&b)const{return pos<b.pos;}
}a[maxn];
signed main() {
#ifdef local
freopen("input2.txt","r",stdin);
#endif // local
#define int register int
cin>>n>>m;
for(ll i=1;i<=n;i++)pos[i]=read();sort(pos+1,pos+1+n);
for(ll i=1;i<=m;i++){
a[i].pos=read(),a[i].num=read(),S+=a[i].num;
}
sort(a+1,a+1+m);
if(S<n){
cout<<-1<<en;return 0;
}
for(int i=1;i<=n;i++)dp[0][i]=inf;
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
sum[j]=sum[j-1]+abs(pos[j]-a[i].pos);
}
int l=1,r=0;
#define ele(x) dp[i-1][x]-sum[x]
for(int j=0;j<=n;j++){
while(l<=r and j-q[l]>a[i].num)l+=1;
while(l<=r and ele(j)<=ele(q[r]))r-=1;
q[++r]=j;
dp[i][j]=ele(q[l])+sum[j];
}
}
printf("%lld\n",dp[m][n]);
return 0;
}