[CodeForces-797F]Mice and Holes
题目大意:
在一条直线上,有n个老鼠,m个洞。
每个老鼠i都有一个初始位置x[i]。
每个洞i都有一个固定位置p[i]和容量限制c[i]。
求所有老鼠都进洞的最小距离总和。
思路:
动态规划。
用f[i][j]表示前i个洞、前j只老鼠的最小距离总和。
用sum[i][j]表示前j个老鼠都进入第i个洞的距离总和。
可以得到以下DP方程:
f[i][j]=min{f[i-1][k]-sum[i][k]|k<=j}+sum[i][j]。
然后就MLE,发现sum可以每次求出来,f如果倒着推,也可以省掉一维。
这样空间复杂度就是O(n)的,时间复杂度是O(n^2m)的,在第42个点TLE了。
考虑使用单调队列维护f[i-1][k]-sum[i][k]的min,做到O(nm)。
1 #include<deque> 2 #include<cstdio> 3 #include<cctype> 4 #include<algorithm> 5 inline int getint() { 6 register char ch; 7 register bool neg=false; 8 while(!isdigit(ch=getchar())) if(ch=='-') neg=true; 9 register int x=ch^'0'; 10 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 11 return neg?-x:x; 12 } 13 const long long inf=0x7fffffffffffffffll; 14 const int N=5001; 15 int x[N]; 16 struct Hole { 17 int p,c; 18 bool operator < (const Hole &another) const { 19 return p<another.p; 20 } 21 }; 22 Hole h[N]; 23 long long f[2][N],sum[N]; 24 std::deque<int> q; 25 int main() { 26 int n=getint(),m=getint(); 27 for(register int i=1;i<=n;i++) { 28 x[i]=getint(); 29 } 30 for(register int i=1;i<=m;i++) { 31 h[i]=(Hole){getint(),getint()}; 32 } 33 std::sort(&x[1],&x[n+1]); 34 std::sort(&h[1],&h[m+1]); 35 std::fill(&f[0][1],&f[0][n+1],inf); 36 for(register int i=1;i<=m;i++) { 37 for(register int j=1;j<=n;j++) { 38 sum[j]=sum[j-1]+std::abs(h[i].p-x[j]); 39 } 40 q.clear(); 41 q.push_back(0); 42 for(register int j=1;j<=n;j++) { 43 while(!q.empty()&&j-q.front()>h[i].c) { 44 q.pop_front(); 45 } 46 while(!q.empty()&&f[!(i&1)][j]-sum[j]<=f[!(i&1)][q.back()]-sum[q.back()]) { 47 q.pop_back(); 48 } 49 q.push_back(j); 50 f[i&1][j]=f[!(i&1)][q.front()]+sum[j]-sum[q.front()]; 51 } 52 } 53 printf("%I64d\n",f[m&1][n]!=inf?f[m&1][n]:-1); 54 return 0; 55 }