码迷,mamicode.com
首页 > 其他好文 > 详细

Mice and Holes CodeForces - 797F

时间:2017-09-12 19:51:06      阅读:196      评论:0      收藏:0      [点我收藏+]

标签:long   std   names   logs   size   target   return   ems   .net   

Mice and Holes CodeForces - 797F

题意:有n只老鼠和m个洞,都在一个数轴上,老鼠坐标为x[1],...,x[n],洞的坐标为p[1],...,p[m],每个洞能容纳的老鼠为c[1],...,c[m],问所有老鼠都躲到洞里后每只老鼠跑的距离之和的最小值。

分析:

如果不给出洞和老鼠的顺序的话,就需要集合操作,基本就是枚举,很慢不考虑。

因此,按坐标顺序排序洞和老鼠,然后定义状态:ans[i][j]表示前i个洞放前j个老鼠最小距离和。

这么做是由于如果有老鼠跑的路线交叠了,那么就一定不是最好的答案。而先排序后这么定义状态,就隐含了只能是前i-1个洞放前k个老鼠,然后第i个洞放第k+1到第j个老鼠,路线不交叠。

(以下部分自己想不到)

然而实际做的时候不一定能想到,这时一定要大胆尝试(比如试一试排序,很可能一排序就能定义出状态了)。

那么ans[i][j]=min(ans[i-1][j]+0,ans[i-1][j-1]+{ j ~ j 的点到i距离和},ans[i-1][j-2]+{ j-1 ~ j 的点到i距离和}...,ans[i-1][j-c[i]]+{ j-c[i]+1 ~ j 的点到i的距离和})

再看ans[i][j-1]=min(ans[i-1][j-1]+0,ans[i-1][j-2]+{ j-1 ~ j-1 的点到i距离和},...,ans[i-1][j-c[i]-1]+{ j-c[i] ~ j-1 的点到i距离和})

仔细看很像取一个"滑动窗口"中最小值,但形式不可以加速,还是太慢。

因此变形一下:

ans[i][j]=min(ans[i-1][j]+0,ans[i-1][j-1] + 1到j的点到i距离和 - 1到(j-1)的点到i距离和,ans[i-1][j-2] + 1到j的点到i距离和 - 1到(j-2)的点到i距离和,...,ans[i-1][j-c[i]] + 1到j的点到i距离和 - 1到(j-c[i])的点到i距离和)
ans[i][j-1]=min(ans[i-1][j-1]+0,ans[i-1][j-2] + 1到j-1的点到i距离和 - 1到j-2的点到i距离和,...,ans[i-1][j-c[i]-1] + 1到j-1的点到i距离和 - 1到j-c[i]-1的点到i距离和)

也就是,ans[i][j]=1到j的点到i距离和 + min{ans[i-1][j-k] - 1到j-k的点到点i距离和}(0<=k<=c[i])

ans[i][j-1]=1到j-1的点到i距离和 + min{ans[i-1][j-k-1]-1到j-k-1的点到点i距离和}(0<=k<=c[i]-1)

也就是,ans[i][j]=1到j的点到i距离和 + min(ans[i-1][j]-1到j的点到i距离和,...,ans[i-1][j-c[i]]-1到j-c[i]的点到i距离和)

ans[i][j-1]=1到j-1的点到i距离和 + min(ans[i-1][j-1]-1到j-1的地点到i距离和,...,ans[i-1][j-c[i]-1]-1到j-c[i]-1的点到i距离和)

这样就可以每次i变化时用单调队列维护min{ans[i-1][j-..]-..}。

还有,ans[i][..]只跟ans[i-1][..]有关,可以用滚动数组省空间。

 1 #include<cstdio>
 2 #include<cstring> 
 3 #include<algorithm>
 4 using namespace std;
 5 typedef long long LL;//曾经忘开LL
 6 struct Hole
 7 {
 8     LL p,c;
 9     bool operator<(const Hole& b) const
10     {
11         return p<b.p; 
12     }
13 }h[5010];
14 LL n,m;
15 LL x[5010];
16 LL ans[2][5010];
17 //曾经写错成ans[5010][2]
18 LL q[5010],l,r,i1;
19 LL s1[5010];//表示前i个洞容纳的总老鼠数量
20 LL s2[5010];//s2[j]表示预处理出的1~j的老鼠到i距离和
21 int main()
22 {
23     LL i,j;
24     scanf("%I64d%I64d",&n,&m);
25     for(i=1;i<=n;i++)
26         scanf("%I64d",&x[i]);
27     for(i=1;i<=m;i++)
28         scanf("%I64d%I64d",&h[i].p,&h[i].c);
29     sort(x+1,x+n+1);
30     sort(h+1,h+m+1);
31     for(i=1;i<=m;i++)
32         s1[i]=s1[i-1]+h[i].c;
33     memset(ans,0x3f,sizeof(ans));
34     ans[0][0]=0;//曾经误将ans[0][..]全部置0
35     if(n>s1[m])
36     {
37         printf("-1");
38         return 0;
39     }
40     for(i=1;i<=m;i++)
41     {
42         i1^=1;
43         l=r=0;
44         for(j=1;j<=min(s1[i],n);j++)
45             s2[j]=s2[j-1]+abs(x[j]-h[i].p);
46         //q[r++]=0;
47         for(j=0;j<=min(s1[i],n);j++)//曾经误将初始当做1
48         {
49             if(r>l&&q[l]<j-h[i].c)    l++;//第j个要考虑的是j-c[i] ~ j,也就是去掉j-c[i]之前的,向单调队列中加入j
50             while(r>l&&ans[i1^1][q[r-1]]-s2[q[r-1]]>=ans[i1^1][j]-s2[j])
51                 r--;
52             q[r++]=j;
53             ans[i1][j]=ans[i1^1][q[l]]-s2[q[l]]+s2[j];
54         }
55     }
56     printf("%I64d",ans[m%2][n]);
57     return 0;
58 }

Mice and Holes CodeForces - 797F

标签:long   std   names   logs   size   target   return   ems   .net   

原文地址:http://www.cnblogs.com/hehe54321/p/cf-797f.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!