P2541 [USACO16DEC] Robotic Cow Herd P 题解
Nuyoah_awa · · 题解
题目大意
题目抽象成一个
题目分析
我们不妨将答案表格排个序,很容易发现最小一列一定是所有行最小值组成的,然后我们来考虑第二小的列,简单思考可得,这一列一定是第一列其中一个值替换成另一个值所得。
我们将这一结论推广,我们设一列为一个状态,通过这一列我们将其中任意一个值改为比这个值大的那个值就可以直接得到另一个比这个状态稍大的状态,由此我们可以得到所有状态。
然后我们可以以最小状态为基础,衍生其他状态,找到最小的
然后时间复杂度就是
很明显过不了,我们发现时间复杂度较大的原因是对于每个状态,我们都会派生出
为优化算法,我们可以考虑更改派生方法使之不会重复,从而优化这一部分的时间。
我们发现对于所有状态,我们都可以找到一个点
我们考虑对于
-
将
p 向右一列,即p_{x, y} \to p'_{x, y+1} -
将
p 向下一行,即p_{x, y} \to p'_{x+1, y} -
当
y = 2 ,p 向左一行,同时下一行的点向右一列。
非常巧妙的方法,同样也可以派生所有的状态,不过说实话非常难想。
时间复杂度是
code
#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
#define int long long
using namespace std;
const int N = 1e5 + 5, INF = 2e18;
struct cow{
int len, d[20], val;
}p[N];
struct node{
int val, x, y;
};
int n, k, ans;
priority_queue <node> q;
bool cmp(int x, int y){return x < y;}
bool cmp_val(cow x, cow y){return x.val < y.val;}
bool operator < (node u, node v){return u.val > v.val;}
signed main()
{
scanf("%lld %lld", &n, &k);
for(int i = 1;i <= n;i++)
{
scanf("%lld", &p[i].len);
for(int j = 1;j <= p[i].len;j++)
scanf("%lld", &p[i].d[j]);
p[i].d[p[i].len+1] = INF;
sort(p[i].d + 1, p[i].d + p[i].len + 1, cmp);
p[i].val = p[i].d[2] - p[i].d[1];
ans += p[i].d[1];
}
sort(p + 1, p + n + 1, cmp_val);
q.push({ans - p[1].d[1] + p[1].d[2], 1, 2});
for(int i = 1;i < k;i++)
{
node u = q.top();
q.pop();
ans += u.val;
q.push({u.val - p[u.x].d[u.y] + p[u.x].d[u.y+1], u.x, u.y+1});
if(u.x != n)
q.push({u.val - p[u.x+1].d[1] + p[u.x+1].d[2], u.x+1, 2});
if(u.x != n && u.y == 2)
q.push({u.val - p[u.x+1].d[1] + p[u.x+1].d[2] - p[u.x].d[2] + p[u.x].d[1], u.x+1, 2});
}
printf("%lld", ans);
return 0;
}